Viewports and User Interaction

Tom Kelliher, CS 320

Mar. 31, 2000

Administrivia

Announcements

Assignment

From Last Time

Dealing with window resizing: viewports, aspect ratios.

Outline

  1. Modifying viewport.c to work with arbitrary aspect ratios.

  2. User interaction, paint.c

Coming Up

Continuing interactive graphics.

Controlling the Viewport

Experimentation with viewport.c

  1. Define the aspect ratio as:

    Given particular values of w and h, compute the proper values for gww and gwh.

  2. Modify viewport.c so that:
    1. ASPECT_RATIO and INITIAL_HEIGHT are #define constants.

    2. gww and gwh are initialized from those two constants.

    3. Modify reshape() to properly set gww and gwh after a reshape event.

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
Thu Mar 30 19:16:58 EST 2000
Tom Kelliher