OpenGL: let’s break it down

Ok, so now that we’ve got makefiles down, let’s talk about the structure of the actual program. I know this is the scary bit, but we’ll get through this together. The image above is my basic graphics program. It produces a single, blank white window. There’s no text in the title bar and the only way to interact with it is to press ‘q’ to exit.

Now, to the breakdown. First, let’s take a look at the headers. I like to keep my standard OpenGL headers in their own header file called glglobal.h. Here’s what that looks like:

#if defined (WIN32)
#include 
#endif

#if defined(_APPLE_)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

#include "Utils.h"

That’s the whole thing. Except for the last line, this is universal and can be used on any computer since it checks the OS. We’ll take a quick look at Utils.h but I’m not going to go in depth on the implementation. You can feel free to implement these yourself, they’re very helpful.

#ifndef DESUTILS_H
#define DESUTILS_H

// This will sleep for ms milliseconds.  It calls nanosleep().
void delay(int ms);

extern void setWorldWin(GLdouble left,GLdouble right,
	GLdouble bottom,GLdouble top);

extern void setViewPort(GLint left,GLint right,GLint bottom,GLint top);

#endif

The delay function is just a wrapper for nanosleep because I don’t like converting from milliseconds to nanoseconds. I’ll confess I don’t remember why I wrote setWorldWin. It’s not in the basic program above and looking at the implementation didn’t reveal any specific purpose. SetViewPort exists for the sheer purpose of simplifying entry of the window dimensions. glViewport takes arguments for bottom left coordinates x,y and then the width and height of the window. But that irritates me. The beauty of programming is you can write a wrapper function for just about anything.

Onward! Next up, the initialization function.

void myInit(){
	glClearColor(1.0,1.0,1.0,0.0);
	glColor3f(0.0f,0.0f,0.0f);
	glPointSize(2.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble) screenW, 0.0, (GLdouble) screenH);
}

This one sets up your window, let’s take a look,

  • glClearColor: this sets the background color of your window. the arguments it takes are red, green, blue, alpha. All values must be between 0 and 1. Alpha sets the opaque-ness of the background but I don’t really see any difference  between 0.0 alpha and 1.0 alpha. If you know how this works more in-depth, please leave me a comment because googling was minimally helpful.
  • glColor3f: this function sets the color of what you draw. Generally you’ll reset this as you go, but I’ve always found it helpful to set it at the beginning just in case. It has definitely happened to me where I couldn’t figure out what the problem with my drawing function was and it turned out to be that I’d forgotten to set the color.
  • glPointSize: you may have guessed it, but this function sets the point size. It takes a GLfloat and defaults to 1.0 if you don’t set it.
  • glMatrixMode: this sets the matrix stack future matrix operations will be applied to. You have 3 options for this one,
    • GL_MODELVIEW
    • GL_PROJECTION
    • GL_TEXTURE
    • GL_COLOR
  • glLoadIdentity: this function replaces whatever the current matrix is with the identity matrix. we’re not going to worry about that too much right now
  • glOrtho2d: last, but not least, this function sets up a 2D orthographic viewing area. It takes four arguments, all of type GLdouble in the order left, right, bottom, top. they set up the horizontal and vertical clipping planes.

Ok, guys, stay with me. We’re going to skip to the main() function now.

int main(int argc, char** argv){
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(screenW,screenH);
	glutInitWindowPosition(200,200);
	glutCreateWindow("");
	glutDisplayFunc(myDisplay);
	glutKeyboardFunc(qexit);
	myInit();
	glutMainLoop();
}

Most of the time, especially if you’re a relatively novice programmer, main() takes no arguments. Argc is the number of command line arguments, argv is an array of character pointers that is the list of arguments. argv[0] is always the program name. The glutInit function takes the address of argc and argv (which is already an address). This function initializes the glut (short for GLutilities) library. So let’s take a quick tour through the main function.

  • glutInitDisplayMode: takes one argument which is usually the bitwise OR of Glut display mode bit masks. You can read about the options here.
  • glutInitWindowSize: sets the size of the window. At the beginning of the program I set constants for screen width and height that are used here and in the gluOrtho2d function in the init function. I’ve found it’s dangerous to not set these as variables because if you update one set of values and not the other, you’ll get some very wonky results.
  • glutCreateWindow: creates the window, takes a string argument of what you want in the title bar. If you have any short instructions, such as “press q to exit” this is a good place for them
  • glutDisplayFunction: takes a function as an argument, this is the one that does the heavy lifting of actually calculating and displaying your program
  • glutKeyboardFuntion: sets up a handler for keyboard output. The handler in this function comes from my personal library and is as simple as
    • if(keyboard input is q or Q) { close window }
  • myInit: the function we ran through above that initializes all the junk
  • glutMainLoop: this function just runs the display function passed to glutDisplayFunction over and over

There we go! You made it through the hard bits! Perhaps you can understand why I keep this all in a template now. Finally let’s take a quick look at the display function stub.

void myDisplay(){
	glClear(GL_COLOR_BUFFER_BIT);

	glFlush();
}

So this is it, the real deal. Any time you’re going to put something new on the screen, you want to call glClears so you’re not drawing endlessly over your old shapes. glFlush pushes the drawing or image you’ve created to the window buffer to be shown.

It’s as easy as that! (please, sense my sarcasm) If you have any questions about this post or there’s another graphics related topic you’d like me to cover, please leave a comment below

Happy coding!

Advertisements