CPSC 453

Lab 1 - Hello World in OpenGL



The "Hello World" program for C++ should be familiar to you.

 #include <iostream>
 using namespace std;

 int main ()
 {
   cout << "Hello World!";
   return 0;
 }

For a line-by-line description, see here.


Of course, this is not very interesting for a graphics course. What is a "Hello World" equivalent in graphics? We'll at least need to open a window with an OpenGL rendering context and display something.

The main function isn't much longer than before:

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

 int main(int argc, char** argv) 
 {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowSize(640, 480);
	glutCreateWindow("Hello World GL");
	glutDisplayFunc(DrawGL);
	glutReshapeFunc(ResizeGL);
	InitGL();
	glutMainLoop();
	return 0;
 }

But just what is going on here? What are all these "glut" functions and what is being passed to them. Let's skip to the glutDisplayFunc() call -- what should we pass to it? According to the intarweb, the function prototype looks like this:

 void glutDisplayFunc(void (*func)(void));

And now we get into the best part of C++ programming -- pointers! Not just pointers, but function pointers!

GLUT, like other window managers, operates on a callback system. When an event occurs, such as a request for redrawing the window contents, GLUT will call your registered function (such as DrawGL(), in this case).

So we need to write a couple of functions, DrawGL() and ResizeGL(), and pass them to GLUT to register for the callbacks. Here's what the other functions might look like:

DrawGL():

 // This is where you draw your stuff to the screen
 // (shouldn't be doing heavy computations in here though)
 void DrawGL() 
 {
	glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
	glLoadIdentity();

	char* str = "Hello World";
	int len = 11, i;

	glRasterPos2d(0, 0);
	for (i=0; i < len; i++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str[i]);

	glutSwapBuffers();
 }

ResizeGL():

 // This is where you define your viewing projection
 // Called by the window manager whenever the window is resized
 void ResizeGL(int w, int h)
 {
	glViewport(0,0,w,h); // set the drawable region of the window
	glMatrixMode(GL_PROJECTION); // set up the projection matrix
	glLoadIdentity(); // clear any previous transform and set to the identity matrix
	glOrtho(-1,1,-1,1,-1,1); // use an orthographic projection
	glMatrixMode(GL_MODELVIEW); // go back to modelview matrix
 }

The code (find it here) can be compiled with:

 g++ -o helloGL -lGL -lGLU -lglut -lXi -lXmu -L/usr/X11R6/lib helloGL.cpp

Run it by typing

 ./helloGL

and you'll see a window that looks like this:


Exercise:

  • Modify the code to draw actual 3D geometry, such as a colored triangle.

Show solution

Replace the string-drawing code in DrawGL() with something like this:

 glBegin(GL_TRIANGLES);
	glColor3f(1, 0, 0);
	glVertex3f(-0.5,-0.5,0);

	glColor3f(0,1,0);
	glVertex3f(0.5,-0.5,0);

	glColor3f(0,0,1);
	glVertex3f(0,0.5,0);
 glEnd();

The output will look like: