are you ready for a mindfuck ? are you ready for a mindfuck?

....::::Menu::::....
...::About::...
...::Articles::...
...::Contact::...
...::Home & News::...
...::Links & Credits::... OpenGL logo
Valid XHTML 1.0!

Hello World

by Elie De Brauwer

Goal of this file

In this article the elementary basics will be covered, clearing a window to a certain color, drawing a rectangle and we will look at handling changes of the window.

History of this file

  • 11 august 2003: created
  • 12 august 2003: added content

Drawing a rectangle

Clearing

Now what we will do now is create a program, that opens a window, clears the windows to a black color and draws a white rectangle in it.
We clear a window by calling glClear(), glClear takes one parameter, this parameter contains the values of what we want to clear. OpenGL has multiple buffers that can be clear the color buffer (GL_COLOR_BUFFER_BIT), the depth buffer (GL_DEPTH_BUFFER_BIT), the accumulation buffer (GL_ACCUM_BUFFER_BIT) and the stencil buffer (GL_STENCIL_BUFFER_BIT). Currently we only use the color buffer so we call glClear(GL_COLOR_BUFFER_BIT) later one we will want to clear more buffer at a time, we will do this by OR'ing the buffer bit so calling glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) will clear the color buffer and the depth buffer.
Now to define to what color we clear the background we will have to call glClearColor(), glClearColor takes 4 doubles as a parameter the RGBA values (Red, Green, Blue, Alpha, glColor3D on the other hand does not take this alpha value) value of the color we want to clear to. glClearColor(0.0,0.0,0.0,0.0) sets the clear color to black. As long al glClearColor is called before glClear it doesn't matter where it is called, this is because the clearcolor is a state variable, it is registered to OpenGL and once it is registered it can be accessed from anywhere.

Drawing

We draw the rectangle by calling the glRectf() (or glRecti, or glRectd or glRects).This function call takes 4 parameters (x1,y1, x2,y2) but what are the coordinates on the screen ? Simple, we call glOrtho() (6 parameters, the dimensions of the screen, the first two are the minimum and maximum x or horizontal values, the next two are the min and max y or vertical values and the last two are the min and max viewable z coordinates). Calling glOrtho(0.0,1.0,0.0,1.0,-1.0,1.0) would make our window accessible by x coordinates in the range 0...1 and y coordinates in the range 0...1. We don't mind the z coordinates since we are only getting started and we are only working in 2 dimensions. Another option for 2D programs is usign gluOrtho2D. This is basicly the same as glOrtho except that it takes only 4 parameters and keeps de z coordinates fixed to -1.0 and 1.0.

Handling a window resize

Since each project is different I will start by offering you three possible methods of handling a reshape. Each has its advantages and it's disadvantages.

reshape

void reshape(int x,int y){
  glViewport(0,0,x,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,100,0,100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

Let's follow the steps the code takes, first we change the viewable area on the screen to the dimensions of the window (with glViewport), next we say we need to alter the projection matrix (with glMatrixMode we select another matrix, the fact that multiple transformation matrices exist will become clear later). We load the identity matrix, the current matrix and we paste our coordinates on top of the window, lower left corner we give coordinates 0,0 and upper left we give coordinates 100,100. This is the simplest reshape function but when a resize occurs the odds are very high that the image will be taken out of perspective, see image below:

hello1

The glViewport() function takes 4 parameters, the last two define the size of the rectangle that can be used to draw in and the first two parameters define the lower left corner of that rectangle.

reshape1

void reshape1(int x,int y){
  glViewport(0,0,x,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,x,0,y);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

When we use this reshape function we can be certain of 2 things. a) the image will in pixel size will always be the same and b) it will never be taken out of proportion, this is because we by mapping its own sizes to the window we achieve that a point with coordinates (a,b) will be exactly a pixels away from the lower left corner (horizontal) en b pixels away from the lower left corner (vertical). But image a 1000 by 1000 pixels square on a monitor that does 1600x1200 and one one that does 640x480.

hello2

reshape2

void reshape2(int x,int y){
  if(x<y)
    glViewport(0,(y-x)/2,x,x);
  else
    glViewport((x-y)/2,0,y,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,100,0,100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

The third solution uses the biggest possible square that can be used in the window and uses that as working area, since there are no square screen this means a waste of space but on the other hand, images are scaled, and not taken out of proportion. Currently this solution will do fine for our next steps into OpenGL and this reshape function will be used in the next articles.

hello3

The program

You can change the reshape functions by using the keys 1, 2 and 3, you can change the background color between green and black by using the g and b keys and quit by pressing q.

#include <iostream>
#include <cstdlib>                // for exit()
#include <GL/glut.h>              // also includes GL/gl.h and GL/glu.h
using namespace std;

typedef unsigned char uchar;

// callback prototypes
void disp(void);
void reshape(int x, int y);
void reshape1(int x, int y);
void reshape2(int x, int y);
void keyb(uchar key, int x, int y);


////////////////////////////////
// main
int main(int argc, char **argv){

  glutInit(&argc, argv);
  // no double buffering since we don't need no animations
  glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
  glutInitWindowSize(400,400);
  glutCreateWindow("hello world");

  // clear to black
  glClearColor(0.0,0.0,0.0,0.0);

  glutDisplayFunc(disp);
  glutKeyboardFunc(keyb);
  glutReshapeFunc(reshape);

  glutMainLoop();
  return 0;
}


////////////////
// disp
void disp(void){
  glClear(GL_COLOR_BUFFER_BIT);
  // draw a white rectangle (only 3 parameters, no alpha)
  glColor3d(1.0,1.0,1.0);
  glRectf(25,25,75,75);
  // update the screen, not needed when using double
  // buffering and glutSwapBuffers()
  glFlush();
}

//////////////////////////
// reshape
void reshape(int x,int y){
  glViewport(0,0,x,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,100,0,100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  /* this reshape maps the coordinates of the screen to [0,100] and [0,100] this can
     take everything out of proportion when resized
  */
}

///////////////////////////
// reshape1
void reshape1(int x,int y){
  glViewport(0,0,x,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,x,0,y);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  /* this won't take anything out of proportion but it won't scale the image either
     the height and width of the window in pixels determine the size of the square
   */
}

//////////////////////////
// reshape2
void reshape2(int x,int y){
  if(x<y)
    glViewport(0,(y-x)/2,x,x);
  else
    glViewport((x-y)/2,0,y,y);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,100,0,100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  /* this will scale the image but keep the area available to OpenGL for drawing a square
     so nothing will be taken out of proportion, not the entire window is accesible.
  */

}

///////////////////////////////////
// keyb
void keyb(uchar key, int x, int y){
  switch(key){
  case '1':
    glutReshapeFunc(reshape);
    cout << "Selected reshape " << endl;
    glutPostRedisplay();
    break;
  case '2':
    glutReshapeFunc(reshape1);
    cout << "Selected reshape1" << endl;
    glutPostRedisplay();
    break;
  case '3':
    glutReshapeFunc(reshape2);
    cout << "Selected reshape2" << endl;
    glutPostRedisplay();
    break;
  case 'g':
    glClearColor(0.0,1.0,0.0,0.0);
    cout << "Will now clear to green" << endl;
    glutPostRedisplay();
    break;
  case 'b':
    glClearColor(0.0,0.0,0.0,0.0);
    cout << "Will now clear to black" << endl;
    glutPostRedisplay();
    break;
  case 'q':
    exit(0);
    break;
  }
}
Or download the source code.