02/09/04

We talked about the stack operator. The OpenGL stack data structure can be used to keep the matrix and its attribute.
At the beginning of a display list, place:

glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix( );

At the end place:
glPopAttrib( );
glPopMatrix( );

If you are not sure about which number to use for a list, use glGenLists(number). This returns the first integer (or base) of number consecutive integers that are unused labels.

The we talk about using display list to generate text:
We can define either the standard 96 printable ASCII characters or we can define patterns for a 256-character extended ASCII character set.

void OurFont( char c)
{
     switch( c )
     {
               case ‘a’:
    …
    break;
    case ‘A’:
    …
    break;
    …
    }
}

We talked about the piece of code that generated letter O in the Lab (2):
Suppose we want to display letter O and we wish to fit it in a unit square:

     switch( c )
     {
         case ‘O’;
       glTranslatef(0.5, 0.5, 0.0); // move to center
       glBegin(GL_QUAD_STRIP);
                  for( I = 0; I <= 12; I++) // 12 vertices
                 {
        angle = 3.14159/6.0 * I; // 30 degrees in radians
         glVertex2f(0.4*cos(angle), 0.4*sin(angle));
          glVertex2f(0.5*cos(angle), 0.5*sin(angle));
    }
    glEnd( );
    glTranslatef(0.5, -0.5,  0.0) ; //move to lower right
         break;
         …
    }
Then we talk about an alternative for printing text:
Previous method requires us to create all letters.  We prefer to use an existing font, rather than to define our own.  GLUT provides a few raster and stroke fonts. 

We can access a single character from a monotype (evenly spaced) font by the function call:
glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, int character)

GLUT_STROKE_ROMAN provides proportionally spaced characters with a size of approximately 120 units maximum. Note that this may not be an appropriate size for your program, thus resizing may be needed.

Raster or bitmap characters are produced in a similar manner. For example:
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, int  character)

will produce an 8x13 character. 
The position is defined directly in the frame buffer and are not subject to geometric transformations.  A raster position will keep the position of the next raster primitive.  This position can be defined using Raster-Pos*( ).

If a character have a different width, we can use the function glutBitmapWidth(font, char)
To return the width of a particular character.
glRasterPos2i(rx, ry);
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, k);
rx += glutBitmapWidth(GLUT_BITMAP_8_BY_13, k);

Here is a program that uses both methods to display Oops.  See the comments to see how you activate both methods:
/* Program draw fonts (draw?) yes
Link glut32.lib  opengl32.lib  glu32.lib*/
#include<math.h>
#include <GL/glut.h>
void myinit(void)
{

        /* attributes */
        glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
        glColor3f(0.0, 0.0, 0.0); /* draw in black */
        /* set up viewing */
        /* 50 x 50 window with origin lower left */
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-50,50 , -50, 50);
        glMatrixMode(GL_MODELVIEW);
}

void display( void )
{
        float angle=0;

     glClear(GL_COLOR_BUFFER_BIT);  /*clear the window */

/* uncomment this comment to get the O at the beginning using
     glTranslatef(5, 5, 0.0);
     glBegin(GL_QUAD_STRIP);
     for( int I = 0; I <= 12; I++)
     {
        angle = 3.14159/6.0 * I;
         glVertex2f(4*cos(angle), 4*sin(angle));
         glVertex2f(5*cos(angle), 5*sin(angle));
     }   

     glEnd( );

     glTranslatef(5, -5, 0.0) ;

Up to here */

     int rx = 0, ry = 5;
     glRasterPos2i(rx, ry);
     glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'o');
     rx += 8;
     glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'p');
     rx += glutBitmapWidth(GLUT_BITMAP_8_BY_13, 'p');
     glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 's');
     rx += glutBitmapWidth(GLUT_BITMAP_8_BY_13, 's');


     glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
        /* Standard GLUT initialization */
        glutInit(&argc,argv);
        glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); /* default, not needed */
        glutInitWindowSize(500,500); /* 500 x 500 pixel window */
        glutInitWindowPosition(0,0); /* place window top left on display */
        glutCreateWindow("Test"); /* window title */
        glutDisplayFunc(display); /* display callback invoked when window opened */
        myinit(); /* set attributes */
        glutMainLoop(); /* enter event loop */
}

When both methods are used, this program produces an screen that looks like this:

oops

Mouse
We start talking about the mouse call back.

Two types of events are associated with the pointing device. 
    move event: is generated when the mouse is moved with one of the     buttons depressed, for a mouse the mouse event happens when one of     the buttons is depressed or released.
    passive move event: is generated when the mouse is moved without a     button being hold down.

The mouse callback function looks like this:
glutMouseFunc(mouse_callback_func)

void mouse_callback_func(int button, int state, int x, int y)

Within the callback function, we define what action we want to take place if the specified event occurs.  There may be multiple actions defined in the mouse callback function corresponding to the many possible button and state combinations.

Here is the square program.
/* This program illustrates the use of the glut library for
interfacing with a Window System */

/* The program opens a window, clears it to white,
then draws a box at the location of the mouse each time the
left button is clicked. Note that the color of each square
is selected randomly but there is an option for setting the
size.  The right button exits the program

The program also reacts correctly when the window is
moved or resized by clearing the new window to white*/
//Link glut32.lib  opengl32.lib  glu32.lib


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

/* globals */

GLsizei wh = 500, ww = 500; /* initial window size */
GLfloat size = 2.0;   /* half side length of square */


void drawSquare(int x, int y)
{

      y = wh-y;
      glColor3ub( (char) rand()%256, (char) rand()%256, (char) rand()%256);
      glBegin(GL_POLYGON);
            glVertex2f(x+size, y+size);
           glVertex2f(x-size, y+size);
            glVertex2f(x-size, y-size);
           glVertex2f(x+size, y-size);
      glEnd();
      glFlush();
}


/* rehaping routine called whenever window is resized
or moved */

void myReshape(GLsizei w, GLsizei h)
{

/* adjust clipping box */

       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       glOrtho(0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0);
       glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();

/* adjust viewport and clear */

    glViewport(0,0,w,h);
    glClearColor (1.0, 1.0, 1.0, 1.0);
       glClear(GL_COLOR_BUFFER_BIT);
       glFlush();

/* set global size for use by drawing routine */

    ww = w;
       wh = h;
}

void myinit(void)
{

       glViewport(0,0,ww,wh);

/* Pick 2D clipping window to match size of screen window
This choice avoids having to scale object coordinates
each time window is resized */

       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       glOrtho(0.0, (GLdouble) ww , 0.0, (GLdouble) wh , -1.0, 1.0);

/* set clear color to black and clear window */

          glClearColor (1.0, 0.0, 0.0, 1.0);
       glClear(GL_COLOR_BUFFER_BIT);
       glFlush();



/* callback routine for reshape event */

//       glutReshapeFunc(myReshape);

}

void mouse(int btn, int state, int x, int y)
{
      if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)   exit(1);
      // comment this one, uncomment the glutMotionFunc to draw continuous
      if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)   drawSquare(x,y);

}

/* display callback required by GLUT 3.0 */

void display(void)
{}

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

       glutInit(&argc,argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
    glutCreateWindow("square");
       myinit ();
       glutReshapeFunc (myReshape);
       glutMouseFunc (mouse);

// uncomment this one, comment the GLUT_LEFT_BUTTON to draw continuous
//      glutMotionFunc(drawSquare);
    glutDisplayFunc(display);

       glutMainLoop();
    return 0;
}

This can produce a drawing if you have motion involved or simgle squares if you decide to have left button to do so.