Mondrian Example Program

int   Times = 100;
int   FillFlag  = 1;
long  Seed = 0;

void
DrawRect( float x1, float y1, float x2, float y2, int FillFlag )
{
[1] glBegin(FillFlag ? GL_QUADS : GL_LINE_LOOP);
        glVertex2f(x1, y1);
        glVertex2f(x2, y1);
        glVertex2f(x2, y2);
        glVertex2f(x1, y2);
    glEnd();
}

void
DrawMondrian(void)
{
    int i;
    float x1, y1, x2, y2;
    float r, g, b;

[2] glClearColor(0, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);

[3] srand48(Seed);
    for( i = 0; i < Times; i++ ) {
        r = drand48();  // drand48() returns a value between 0 and 1
        g = drand48();
        b = drand48();
        glColor3f( r, g, b );

        x1 = drand48();
        y1 = drand48();
        x2 = drand48();
        y2 = drand48();
        DrawRect( x1, y1, x2, y2, FillFlag );
    }

[4] glFinish();
}





[1] The following code fragment draws a simple rectangle: (x1,y1) is the lower-left corner, and (x2,y2) is the upper right corner.

    
    glBegin(FillFlag ? GL_QUADS : GL_LINE_LOOP);
        glVertex2f(x1, y1);
        glVertex2f(x2, y1);
        glVertex2f(x2, y2);
        glVertex2f(x1, y2);
    glEnd();

Graphics primitives are constructed from sequences of vertices bracketed with glBegin/glEnd. The argument to glBegin describes what type of primitive is being defined. In this case we test FillFlag to control whether the rectangle is drawn as a filled polygon (GL_QUADS), or as a sequence of lines (GL_LINE_LOOP).

The glVertex command defines a single vertex. This command exists in many forms. The version used in this example, glVertex2f, specifies a point with 2 floats. Other forms of glVertex use different data types as arguments (ints, floats, arrays of floats, etc.) and have different numbers of dimensions (2d and 3d).

The rectangle is specified by giving a sequence of vertices. These vertices define a polygon in counterclockwise order. That is, (x1,y1) is the lower left corner, (x2,y1) is the lower right corner, and so on.

[2] This code sequence sets the background ClearColor to black (0,0,0), and then clears the color framebuffer to black. The fourth color coordinate sets the alpha value to be 1; ignore this for now.

    
    glClearColor(0, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);

The constant GL_COLOR_BUFFER_BIT commands the system to just clear the color buffer. Later, we will see that there are other image buffers in the system that may be simultaneously cleared to their background values with this command.

[3] This loop draws a bunch of rectangles, with random corner positions and colors.

    
    for( i = 0; i < Times; i++ ) {
        glColor3f( r, g, b );
        DrawRect( x1, y1, x2, y2, FillFlag );
    }

The glColor3f command sets the current color. All graphics primitives that are defined are drawn using the current color. The glColor command is one of many commands that change the graphics state. The graphics state contains attributes that control how graphics primitive are drawn. Besides color, there are attributes such as linewidth, linestyle, etc.

Just as there are many forms of the glVertex command to accomodate different data formats, there are different forms of glColor command.

DrawMondrian is called initially to create the Mondrain. However, it may be called again to update the current display if it needs to be redrawn for some reason. To ensure that the same image is redrawn, the seed of the random number generator is set to a stored value so that the sequence of random positions and colors are always the same.

[4] Graphics commands are streamed to the graphics system, and for various reasons may not be executed immediately. To ensure that all the commands are executed, and that the image being shown is what is drawn, call glFinish.

CS248: Introduction to Computer Graphics, Pat Hanrahan