paint.c

Tom Kelliher, CS 320

Feb. 11, 1998

Announcements:

From last time:

  1. Overview of OpenGL, GLUT functions

Outline:

Assignment: Run and read viewport.c.

paint.c

  1. Stripped-down paint program: lines, rectangles, triangles, points. Color, fill, clear canvas.

  2. User interaction: right-button menus, left-button selections.

  3. Pick determination.

  4. Text and Time display in the idle function.

  5. Window reshaping.

Coordinate systems

  1. Rendering origin for OpenGL.

  2. Window and mouse coordinate origin for the window system.

  3. Translating.

Menus and Sub-Menus

int main()
{

    // ...

    c_menu = glutCreateMenu(color_menu);
    glutAddMenuEntry("Red",1);
    glutAddMenuEntry("Green",2);
    glutAddMenuEntry("Blue",3);
    glutAddMenuEntry("Cyan",4);
    glutAddMenuEntry("Magenta",5);
    glutAddMenuEntry("Yellow",6);
    glutAddMenuEntry("White",7);
    glutAddMenuEntry("Black",8);
    p_menu = glutCreateMenu(pixel_menu);
    glutAddMenuEntry("increase pixel size", 1);
    glutAddMenuEntry("decrease pixel size", 2);
    f_menu = glutCreateMenu(fill_menu);
    glutAddMenuEntry("fill on", 1);
    glutAddMenuEntry("fill off", 2);
    glutCreateMenu(right_menu);
    glutAddSubMenu("Colors", c_menu);
    glutAddSubMenu("Pixel Size", p_menu);
    glutAddSubMenu("Fill", f_menu);
    glutAddMenuEntry("clear",2);
    glutAddMenuEntry("quit",1);
    glutAttachMenu(GLUT_RIGHT_BUTTON);

    // ...

}


void color_menu(int id)
{
   glutIdleFunc(NULL);
   if(id == 1) {r = 1.0; g = 0.0; b = 0.0;}
   else if(id == 2) {r = 0.0; g = 1.0; b = 0.0;}
   else if(id == 3) {r = 0.0; g = 0.0; b = 1.0;}
   else if(id == 4) {r = 0.0; g = 1.0; b = 1.0;}
   else if(id == 5) {r = 1.0; g = 0.0; b = 1.0;}
   else if(id == 6) {r = 1.0; g = 1.0; b = 0.0;}
   else if(id == 7) {r = 1.0; g = 1.0; b = 1.0;}
   else if(id == 8) {r = 0.0; g = 0.0; b = 0.0;}
   glutIdleFunc(idle);
}

Pick Determination and Drawing States

  1. Mouse function called into play here.

  2. Note that right button taken out of action.

  3. Canvas icons: four in row, upper-left. Dimensions?

int pick(int x, int y)
{
    y = wh - y;
    if(y < wh-ww/10) return 0;
    else if(x < ww/10) return 1;
    else if(x < ww/5) return 2;
    else if(x < 3*ww/10) return 3;
    else if(x < 2*ww/5) return 4;
    else return 0;
}

void mouse(int btn, int state, int x, int y)
{
    static int draw_mode = 0; /* drawing mode */
    static int count;
    int where;
    static int xp[2],yp[2];
    if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) 
    {
       glPushAttrib(GL_ALL_ATTRIB_BITS);
       glutIdleFunc(NULL);
       
       where = pick(x,y);
       glColor3f(r, g, b);
       if(where != 0)
       {
          count = 0;
          draw_mode = where;
       }
       else if(draw_mode == 1  &&  count == 0)
       {
              count = 1;
              xp[0] = x;
              yp[0] = y;
       }
       else if(draw_mode == 1  &&  count != 0)
       {
              glBegin(GL_LINES); 
                 glVertex2i(x,wh-y);
                 glVertex2i(xp[0],wh-yp[0]);
              glEnd();
              draw_mode=0;
              count=0;
       }
       else if(draw_mode == 2  &&  count == 0)
       {
              count = 1;
              xp[0] = x;
              yp[0] = y;
       }
       else if(draw_mode == 2  &&  count != 0) 
       {
              if(fill) glBegin(GL_POLYGON);
              else glBegin(GL_LINE_LOOP);
                 glVertex2i(x,wh-y);
                 glVertex2i(x,wh-yp[0]);
                 glVertex2i(xp[0],wh-yp[0]);
                 glVertex2i(xp[0],wh-y);
              glEnd();
              draw_mode=0;
              count=0;
       }
       else if(draw_mode == 3  &&  count == 0)
       {
              count = 1;
              xp[0] = x;
              yp[0] = y;
       }
       else if(draw_mode == 3  &&  count == 1)
       {
              count = 2;
              xp[1] = x;
              yp[1] = y;
       }
       else if(draw_mode == 3  &&  count == 2)
       {
              if(fill) glBegin(GL_POLYGON);
              else glBegin(GL_LINE_LOOP);
                 glVertex2i(xp[0],wh-yp[0]);
                 glVertex2i(xp[1],wh-yp[1]);
                 glVertex2i(x,wh-y);
              glEnd();
              draw_mode=0;
              count=0;
       }
       else if(draw_mode == 4 )
       {
          drawSquare(x,y);
          count++;
       }

       glutIdleFunc(idle);
       glPopAttrib();
       glFlush();
     }
}

Text Display

Idea:

  1. Specify starting location of text (world coordinates).

  2. Start writing, specifying font and character.

Example:

void renderString(GLdouble x, GLdouble y, void *font, char *text)
{
   glRasterPos2d(x, y);

   while (text)
   {
      glutBitmapCharacter(font, *text);
      ++text;
   }
}
See man page for glutBitmapCharacter for list of available bitmap fonts.

Idea similar to font cache: display lists. Program example:

base = glGenLists(128);

for(i=0;i<128;i++)
{
   glNewList(base+i, GL_COMPILE);
   glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i);
   glEndList();
}

glListBase(base);
Use:
// Dump time string into out.

glRasterPos2i(ww-80, wh-15);
glColor3f(0.0,0.0,0.0);
glBegin(GL_QUADS);
   glVertex2i(ww-80, wh-15);
   glVertex2i(ww, wh-15);
   glVertex2i(ww, wh);
   glVertex2i(ww-80, wh);
glEnd();
glColor3f(1.0,1.0,1.0);
glCallLists( strlen(out) , GL_BYTE, out);

Time Display in the Idle Function

  1. ``Watery'' appearance.

  2. Constant updating.

  3. Fixes?

  4. Note use of NULL to disable idle function and subsequent re-registration.

Window and Canvas Re-Shaping

  1. Reshape function registered and called on reshape event.

  2. Is passed new window size.

  3. Adjusts clipping rectangle to reflect new canvas size.

  4. Sets viewport to entire window.

  5. Clears canvas.

  6. Calls display() to paint the buttons. (Will display() get the button sizes right?)

  7. Adjusts global canvas size.


Thomas P. Kelliher
Mon Feb 9 11:40:13 EST 1998
Tom Kelliher