Introduction to OpenGL and GLUT
CS-116A: Introduction to Computer Graphics
Instructor: Rob Bruce
Fall 2016

SLIDE 1: OpenGL: History

SLIDE 2: GLUT: OpenGL Utility Toolkit

  • Enables cross-platform, OpenGL programming in a graphical environment on window-based systems such as X windows, OSX, and Microsoft Windows.
  • Contains window resizing and mouse click events. May also contain graphical widgets for GUI.

SLIDE 3: Dissecting a GLUT program in C: main()

  • Step 1 of 12: The skeleton of our main() program.

int main (int argc, char *argv[])
{
}

SLIDE 4: Dissecting a GLUT program in C: main()

  • Step 2 of 12: Defining a status variable, window. This variable will eventually hold one of two values:
  • 1 = window successfully created.
  • 0 = window creation failed

int main (int argc, char *argv[])
{
  int window;
}

SLIDE 5: Dissecting a GLUT program in C: main()

  • Step 3 of 12: glutInit() calls the window manager (Microsoft Windows, Apple OSX, X-windows, etc.) to request a window widget. GLUT will report an error if it is unable to successfully create a window.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
}

SLIDE 6: Dissecting a GLUT program in C: main()

  • Step 4 of 12: glutInitDisplayMode() establishes criteria for how windows will be displayed. We want the following:
  • GLUT_RGBA: Default window mode with 32 bits per pixel (R, G, B, A).
  • GLUT_DOUBLE: Use double buffering.
  • GLUT_ALPHA: Window will use the alpha channel.
  • GLUT_DEPTH: Enable depth buffer. This is important for visibility of stacked images.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
}

SLIDE 7: Dissecting a GLUT program in C: main()

  • Step 5 of 12: glutInitWindowSize() defines the horizontal and vertical pixel resolution of the window we are creating.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
}

SLIDE 8: Dissecting a GLUT program in C: main()

  • Step 6 of 12: glutInitWindowPosition() defines the location where the window should appear on the user's screen. Note: windowing systems (e.g. Microsoft Windows, OSX, etc.) are not obligated to adhere to this value. GLUT merely passes these values to the windowing manager.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
}

SLIDE 9: Dissecting a GLUT program in C: main()

  • Step 7 of 12: glutCreateWindow() defines the title for the window being created. The text, "Drawing a circle" will literally be displayed in the window's title bar. glutcreateWindow() returns 1 on successfully creating the window or 0 on failure.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
}

SLIDE 10: Dissecting a GLUT program in C: main()

  • Step 8 of 12: glutDisplayFunc() allows the user to define the subroutine responsible for displaying the current window being defined. The user-defined subroutine determines what is actually displayed in the window we created with glutCreateWindow().

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
  glutDisplayFunc (&DrawGLScene);
}

SLIDE 11: Dissecting a GLUT program in C: main()

  • Step 9 of 12: glutIdleFunc() allows one to specify the user-defined subroutine to be called when the main GLUT event loop has no events to process. Example: user window contains an animated picture that needs to be redrawn.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
  glutDisplayFunc (&DrawGLScene);
  glutIdleFunc (&DrawGLScene);
}

SLIDE 12: Dissecting a GLUT program in C: main()

  • Step 10 of 12: glutReshapeFunc() allows the user to define a subroutine to be called when the user resizes their window in the window manager (e.g. Microsoft Windows). For example, a window that displays an image would need to be redrawn if the window were resized. This means scaling the image up or down but maintaining its aspect ratio when redrawing the image (e.g. so the image does not appear squashed or stretched).

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
  glutDisplayFunc (&DrawGLScene);
  glutIdleFunc (&DrawGLScene);
  glutReshapeFunc (&ReSizeGLScene);
}

SLIDE 13: Dissecting a GLUT program in C: main()

  • Step 11 of 12: InitGL() is a user defined subroutine. In this subroutine, we will be initializating parameters for the GLUT window we are creating.

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
  glutDisplayFunc (&DrawGLScene);
  glutIdleFunc (&DrawGLScene);
  glutReshapeFunc (&ReSizeGLScene);
  InitGL (1280, 1024);
}

SLIDE 14: Dissecting a GLUT program in C: main()

  • Step 12 of 12: glutMainLoop() is GLUT's main event-driven loop to process events in the window manager (e.g. mouse clicks, keyboard presses, window resizing, etc.).

int main (int argc, char *argv[])
{
  int window;
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize (1280, 1024);
  glutInitWindowPosition (0, 0);
  window = glutCreateWindow ("Drawing a circle");
  glutDisplayFunc (&DrawGLScene);
  glutIdleFunc (&DrawGLScene);
  glutReshapeFunc (&ReSizeGLScene);
  InitGL (1280, 1024);
  glutMainLoop();
}

SLIDE 15: Dissecting a GLUT program in C: main()

  • Our main() calls the following user-defined subroutines:
  • InitGL()
  • ReSizeGLScene()
  • DrawGLScene()

  • We'll dissect InitGL() next...

SLIDE 16: Dissecting a GLUT program in C: InitGL()

  • Step 1 of 10: The skeleton of our InitGL() subroutine.

void InitGL (int width, int height)
{
}

SLIDE 17: Dissecting a GLUT program in C: InitGL()

  • Step 2 of 10: glClearColor() specifies what values to use when color buffer is cleared. The values must be between 0 and 1 inclusive. In our case, we will be clearing the color buffer to all black with no transparency.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
}

SLIDE 18: Dissecting a GLUT program in C: InitGL()

  • Step 3 of 10: glClearDepth() specifies the color depth to be used when the depth buffer is cleared. The rangfe of values is between 0 and 1 inclusive. The default value is 1.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
}

SLIDE 19: Dissecting a GLUT program in C: InitGL()

  • Step 4 of 10: glDepthFunc() specifies the depth comparison function used in the depth buffer to determine if a pixel should be displayed (i.e. visible). The default is GL_LESS.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
}

SLIDE 20: Dissecting a GLUT program in C: InitGL()

  • Step 5 of 10: glEnable() enables depth testing to determine if pixels are visible in the depth buffer.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
}

SLIDE 21: Dissecting a GLUT program in C: InitGL()

  • Step 6 of 10: glShadeModel() specifies a shading technique. The default is GL_SMOOTH.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
  glShadeModel (GL_SMOOTH);
}

SLIDE 22: Dissecting a GLUT program in C: InitGL()

  • Step 7 of 10: glMatrixMode() specifies which matrix mode is used in matrix operations. The default is GL_PROJECTION.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
  glShadeModel (GL_SMOOTH);
  glMatrixMode (GL_PROJECTION);
}

SLIDE 23: Dissecting a GLUT program in C: InitGL()

  • Step 8 of 10: glLoadIdentity() resets the identity matrix to the default state. This affects subsequent operations such as glRotate() or glTranslate(). It is a good idea to initially reset the identity matrix since subsequent operations such as glRotate and glTranslate() are cumulative operations that affect and change the identity matrix.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
  glShadeModel (GL_SMOOTH);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
}

SLIDE 24: Dissecting a GLUT program in C: InitGL()

  • Step 9 of 10: gluPerspective() specifies the view angle (45 degrees) and the aspect ratio of the field of view, and the near and far clipping planes. Note that I'm preserving the aspect ratio of my display window by dividing the window's width by its height. This keeps my perspective view from being squashed or stretched.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
  glShadeModel (GL_SMOOTH);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
  gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
}

SLIDE 25: Dissecting a GLUT program in C: InitGL()

  • Step 10 of 10: glMatrixMode() switch current matrix mode to GL_MODELVIEW matrix stack.

void InitGL (int width, int height)
{
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth (1.0);
  glDepthFunc (GL_LESS);
  glEnable (GL_DEPTH_TEST);
  glShadeModel (GL_SMOOTH);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
  gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
  glMatrixMode (GL_MODELVIEW);
}

SLIDE 26: Dissecting a GLUT program in C: main()

  • Our main() calls the following user-defined subroutines:
  • InitGL()
  • ReSizeGLScene()
  • DrawGLScene()

  • We'll dissect ReSizeGLScene() next...

SLIDE 27: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 1 of 7: The skeleton of our ReSizeGLScene() subroutine.

void ReSizeGLScene (int width, int height)
{
}

SLIDE 28: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 2 of 7: Checking height for value zero ensures we (later) don't divide by zero.

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
}

SLIDE 29: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 3 of 7: glViewport() set the viewport to dimensions of our display window: (0, 0) to (width, height).

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
  glViewport (0, 0, width, height);
}

SLIDE 30: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 4 of 7: glMatrixMode() use the GL_PROJECTION matrix. We will subsequently initialize it in the next step.

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
  glViewport (0, 0, width, height);
  glMatrixMode (GL_PROJECTION);
}

SLIDE 31: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 5 of 7: glLoadIdentity() now initialize the GL_PROJECTION matrix.

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
  glViewport (0, 0, width, height);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
}

SLIDE 32: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 6 of 7: gluPerspective() specifies the view angle (45 degrees) and the aspect ratio of the field of view, and the near and far clipping planes. Note that I'm preserving the aspect ratio of my display window by dividing the window's width by its height. This keeps my perspective view from being squashed or stretched.

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
  glViewport (0, 0, width, height);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
  gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
}

SLIDE 33: Dissecting a GLUT program in C: ReSizeGLScene()

  • Step 7 of 7: glMatrixMode() switch back to GL_MODELVIEW matrix.

void ReSizeGLScene (int width, int height)
{
  if (height == 0)
  {
    height = 1;
  }
  glViewport (0, 0, width, height);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
  gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
  glMatrixMode (GL_MODELVIEW);
}

SLIDE 34: Dissecting a GLUT program in C: main()

  • Our main() calls the following user-defined subroutines:
  • InitGL()
  • ReSizeGLScene()
  • DrawGLScene()

  • We'll dissect DrawGLScene() next...

SLIDE 35: Dissecting a GLUT program in C: DrawGLScene()

  • Step 1 of 12: The skeleton of our DrawGLScene() subroutine.

void DrawGLScene ()
{
}

SLIDE 36: Dissecting a GLUT program in C: DrawGLScene()

  • Step 2 of 12: Define some floating point variables we'll be using to draw a filled circle.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
}

SLIDE 37: Dissecting a GLUT program in C: DrawGLScene()

  • Step 3 of 12: The center of the circle will be located on our screen window at X = 320 pixels.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
}

SLIDE 38: Dissecting a GLUT program in C: DrawGLScene()

  • Step 4 of 12: The center of the circle will be located on our screen window at Y = 220 pixels.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
}

SLIDE 39: Dissecting a GLUT program in C: DrawGLScene()

  • Step 5 of 12: glColor3ub() defines the 8-bit color using unsigned bytes for Red (R), Green (G), and Blue (B) values between 0 and 255 inclusively.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
}

SLIDE 40: Dissecting a GLUT program in C: DrawGLScene()

  • Step 6 of 12: glPolygonMode() defines which sides of an object will be displayed (i.e. front, back, or front and back) and if the object should be drawn filled or unfilled (outline). We are drawing a FILLED circle. The front of the circle will be visible.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
}

SLIDE 41: Dissecting a GLUT program in C: DrawGLScene()

  • Step 7 of 12: glBegin() defines the beginning of a series of drawing commands.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
}

SLIDE 42: Dissecting a GLUT program in C: DrawGLScene()

  • Step 8 of 12: We will be drawing a circle. We'll loop from 0 to 360 degrees in five degree increments. We'll approximate a circle by drawing small straight lines. The circle will appear round.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
  for (theta_degrees = 0.0f; theta_degrees < 360.0f; theta_degrees += 5.0f)
  {
  }
}

SLIDE 43: Dissecting a GLUT program in C: DrawGLScene()

  • Step 9 of 12: Sine and cosine functions require all degree values be converted to radians. Our main loop is in degrees. We'll convert each degree value to radians here.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
  for (theta_degrees = 0.0f; theta_degrees < 360.0f; theta_degrees += 5.0f)
  {
    theta_radians = theta_degrees * M_PI / 180.0f;
  }
}

SLIDE 44: Dissecting a GLUT program in C: DrawGLScene()

  • Step 10 of 12: glVertex3F() defines a vertice on the radius of our circle with X, Y, and Z coordinates. Since we are drawing in only 2-dimensions (X and Y). We'll set the depth value (Z) to zero. Circles are two dimensional.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
  for (theta_degrees = 0.0f; theta_degrees < 360.0f; theta_degrees += 5.0f)
  {
    theta_radians = theta_degrees * M_PI / 180.0f;
    glVertex3f (center_x + cos(theta_radians) * radius, center_y + sin(theta_radians) * radius, 0.0f);
  }
}

SLIDE 45: Dissecting a GLUT program in C: DrawGLScene()

  • Step 11 of 12: glEnd() defines the end of our drawing. We have now finished issuing all the points along the radius of our circle.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
  for (theta_degrees = 0.0f; theta_degrees < 360.0f; theta_degrees += 5.0f)
  {
    theta_radians = theta_degrees * M_PI / 180.0f;
    glVertex3f (center_x + cos(theta_radians) * radius, center_y + sin(theta_radians) * radius, 0.0f);
  }
  glEnd();
}

SLIDE 46: Dissecting a GLUT program in C: DrawGLScene()

  • Step 12 of 12: glFlush() forces OpenGL to push any cached drawing from memory onto the screen.

void DrawGLScene ()
{
  float center_x, center_y, theta_degrees, theta_radians, radius, iterations;
  center_x = 320.0f;
  center_y = 220.0f;
  glColor3ub (255, 255, 0);
  glPolygonMode (GL_FRONT, GL_FILL);
  glBegin (GL_POLYGON);
  for (theta_degrees = 0.0f; theta_degrees < 360.0f; theta_degrees += 5.0f)
  {
    theta_radians = theta_degrees * M_PI / 180.0f;
    glVertex3f (center_x + cos(theta_radians) * radius, center_y + sin(theta_radians) * radius, 0.0f);
  }
  glEnd();
  glFlush();
}

SLIDE 47: Dissecting a GLUT program in C: main()

  • Our main() calls the following user-defined subroutines:
  • InitGL()
  • ReSizeGLScene()
  • DrawGLScene()

  • Next we need to include header files at the top of our program...

SLIDE 48: Dissecting a GLUT program in C: Headers

  • If we are compiling on GNU/Linux, we must include the following headers at the top of our program.

#include <GL/glut.h>
#include <math.h>

  • If we are compiling on a Mac (OSX), we must include the following headers at the top of our program.

#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#include <math.h>

SLIDE 49: Command to compile a GLUT program in C

  • To compile circle.c on GNU/Linux, issue the following command

cc -o circle circle.c -lglut -lGL -lGLU -lX11 -lXmu -lXi -lm

  • To compile circle.c on a MAC (OSX), issue the following command

cc -o circle circle.c -framework GLUT -framework OpenGL -framework Cocoa -lm -Wno-deprecated

SLIDE 50: GLUT implementations