02/09/05

We tallked about the solution to the snow flakes problem.  Also we discussed the solution to Quiz(4).
For the snow flakes, the main thing was to modify the draw_triangle in the Gasket program.

void snow(point2 a, point2 b, int m)
{

/* triangle subdivision using vertex numbers */

point2 c;
point2 d;
point2 e;
point2 f;
if( m >0)
{
glBegin(GL_LINE_STRIP);

c[0] = a[0] + (1.0/3)*(b[0]-a[0]);
c[1] = a[1] + (1.0/3)*(b[1]-a[1]);

f[0] = a[0]+(2.0/3)*(b[0]-a[0]);
f[1] = a[1]+(2.0/3)*(b[1]-a[1]);
d[0] = f[0] - c[0];
d[1] = f[1] - c[1];
e[0] = c[0]+ 0.5* d[0] - sqrt(3)*d[1]/2;
e[1] = c[1] + sqrt(3)*d[0]/2 + 0.5*d[1];
snow(a,c,m-1);
snow(c,e,m-1);
snow(e,f,m-1);
snow(f,b,m-1);
glVertex2fv(a);
glVertex2fv(c);
glVertex2fv(e);
glVertex2fv(f);
glVertex2fv(b);

glEnd();
}
}

The initial points also will change to:

const double PI = 3.141593;
typedef float point2[2];

/* initial triangle */
point2 v[]={{400.0, 100.0}, {100, 100}};
point2 v1[]={{250, 359.807621135331}, {400.0, 100.0}};
point2 v2[]={{100,100}, {250, 359.807621135331}};

The 359.80762....  is the top point of the triangle that I used to build the snow flakes.
The 0th iteration looks like this:

First iteration:

Fith iteration:

For Quiz(4), I asked you to modify the program that drew the big O to draw a square using the same procedure.

This is the program that we used to create the Big O:
static void myinit (void)
{

glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 20, 0, 20);

glMatrixMode(GL_MODELVIEW);

glClearColor (1, 1.0, 1.0, 1.0);

float angle;
listName = glGenLists (1);
glNewList (listName, GL_COMPILE);
glTranslatef(5, 10, 0.0);
glColor3f (1.0, 0.0, 0.0);  /*  current color red  */
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, 10, 0.0); /*  move position  */
glEndList ();

}

If we make two changes:

for(int i = 0; i <= 4; i++)
{
angle = 3.14159/2 * i;
glVertex2f (4*cos(angle), 4*sin(angle));
glVertex2f (5*cos(angle), 5*sin(angle));
}

And the display title to:
glutCreateWindow("Square from Big O");

Then we will get:

Picking
We talked about picking. Picking is an input operation that allows the user to identify an object on the display.  Although, the picking is done by a pointing device, the information returned to the application program is not a position.
Why picking is more difficult in modern systems?
Does a point on the display reversible to its origin?
A pick device is more difficult to implement than the locator device.  There are two ways to do this:
1) selection, involves adjusting the clipping region and viewport such that we can keep track of which primitives in a small clipping region are rendered into a region near the cursor. Creates a hit list. OpenGL supports it.
2) bounding rectangles or extents, this is the smallest rectangle, aligned with the coordinates axes, that contains the object.
3) Use back buffer and an extra rendering.  Involves 4 steps: 1) draw the object in the back buffer with the pick color, 2) Get the position of the mouse using the mouse callback, 3) Use glReadPixels() to find the color at the position in the frame buffer corresponding to the mouse position, 4) Search a table of colors to find which object corresponds to the color read.  Follow these steps by a normal rendering into the back buffer.

Here is an example of how picking can be done using one of these three methods:
/* pick.c    */
// Minor Modification by Rahman Tashakkori - Spring 2004
/* E. Angel, Interactive Computer Graphics */
/* A Top-Down Approach with OpenGL, Third Edition */

/* demonstrates picking used selection mode */

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

void init()
{
glClearColor (0.0, 0.0, 0.0, 0.0);
}

void drawObjects(GLenum mode)
{
glColor3f(1.0, 0.0, 0.0);
glRectf(-0.5, -0.5, 1.0, 1.0);
//    glRectf(-0.5, -0.5, 0.5, 0.5);

glColor3f(0.0, 0.0, 1.0);
glRectf(-1.0, -1.0, 0.5, 0.5);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
drawObjects(GL_RENDER);
glFlush();
}

/*  processHits prints out the contents of the
*  selection array.
*/
void processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLuint ii, jj, names, *ptr;

printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
for (i = 0; i < hits; i++) {    /*  for each hit  */
names = *ptr;
ptr+=3;
for (j = 0; j < names; j++) { /*  for each name */
if(*ptr==1) printf ("red rectangle\n");
else printf ("blue rectangle\n");
ptr++;
}
printf ("\n");
}
}

#define SIZE 512

void mouse(int button, int state, int x, int y)
{
GLuint selectBuf[SIZE];
GLint hits;
GLint viewport[4];

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
glGetIntegerv (GL_VIEWPORT, viewport);

glSelectBuffer (SIZE, selectBuf);
glRenderMode(GL_SELECT);

glInitNames();
glPushName(0);

glMatrixMode (GL_PROJECTION);
glPushMatrix ();
/*  create 5x5 pixel picking region near cursor location    */
gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y),
5.0, 5.0, viewport);
gluOrtho2D (-2.0, 2.0, -2.0, 2.0);
drawObjects(GL_SELECT);

glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glFlush ();

hits = glRenderMode (GL_RENDER);
processHits (hits, selectBuf);

glutPostRedisplay();
}
}

void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
gluOrtho2D (-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'q':
case 'Q':
exit(0);
break;
}
}

/* Main Loop */
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutReshapeFunc (reshape);
glutDisplayFunc(display);
glutMouseFunc (mouse);
glutKeyboardFunc (keyboard);
glutMainLoop();
return 0;

}

The result would be the screen show below and the data provided representing the locations where the click was made on the left mouse button.

And tha Data screen:

That shows that we have red area, red area again, blue, then 5 times outside both (black area), then red, red, and finally a blue.

We start talking about the simple paint program.  Such a paint program should utilize menues and submenus heavily.  Here is a possible schema:

An implementation of this program would be:

/* This program illustrates the use of the glut library for
interfacing with a window system */

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

void mouse(int, int, int, int);
void key(unsigned char, int, int);
void display(void);
void drawSquare(int, int);
void myReshape(GLsizei, GLsizei);

void myinit(void);

void screen_box(int, int, int);
int pick(int, int);

/* globals */

GLsizei wh = 500, ww = 500; /* initial window size */
GLfloat size = 3.0;   /* half side length of square */
int draw_mode = 0; /* drawing mode */
int rx, ry; /*raster position*/
int base;

GLfloat r = 1.0, g = 1.0, b = 1.0; /* drawing color */
int fill = 0; /* fill flag */

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();
}

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

void myReshape(GLsizei w, GLsizei h)
{

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

/* adjust viewport and  clear */

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

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

ww = w;
wh = h;
}

void myinit(void)
{

// char
int i;
/*
base = glGenLists(256);
for(i = 0; i < 255; i++)
{
glNewList(base+i, GL_COMPILE);
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, i);
//    glutStrokeCharacter(GLUT_STROKE_ROMAN, i);
glEndList();
}
glListBase(base);

*/

glViewport(0,0,ww,wh);

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

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

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

glClearColor (0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}

void mouse(int btn, int state, int x, int y)
{
static int count;
int where;
static int xp[2],yp[2];
if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);

where = pick(x,y);
glColor3f(r, g, b);
if(where != 0)
{
count = 0;
draw_mode = where;
}
else switch(draw_mode)
{
case(1): //line
if(count==0)
{
count++;
xp[0] = x;
yp[0] = y;
}
else
{
glBegin(GL_LINES);
glVertex2i(x,wh-y);
glVertex2i(xp[0],wh-yp[0]);
glEnd();
draw_mode=0;
count=0;
}
break;
case(2): //rectangle
if(count == 0)
{
count++;
xp[0] = x;
yp[0] = y;
}
else
{
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;
}
break;
case (3): //Triangle
switch(count)
{
case(0):
count++;
xp[0] = x;
yp[0] = y;
break;
case(1):
count++;
xp[1] = x;
yp[1] = y;
break;
case(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;
}
break;
case(4)://Point
{
drawSquare(x,y);
count++;
}
break;
case(5)://TEXT
{
rx=x;
ry=wh-y;
glRasterPos2i(rx,ry);
count=0;
break;
}
default:
{
rx=x;
ry=wh-y;
glRasterPos2i(rx,ry);
count=0;
}
}

glPopAttrib();
glFlush();
}
}

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

void screen_box(int x, int y, int s )
{
glVertex2i(x, y);
glVertex2i(x+s, y);
glVertex2i(x+s, y+s);
glVertex2i(x, y+s);
glEnd();
}

{
if(id == 1) exit(1);
else display();
}

{

}

{
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;}
}

{
if (id == 1) size = 2 * size;
else if (size > 1) size = size/2;
}

{
if (id == 1) fill = 1;
else fill = 0;
}

void key(unsigned char k, int xx, int yy)
{
if(draw_mode!= 5) return;  //text
glColor3f(0.0,0.0,0.0);
glRasterPos2i(rx,ry);
//    glCallList(k);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, k);
//     glutBitmapCharacter(GLUT_BITMAP_8_BY_13, k);

/*glutStrokeCharacter(GLUT_STROKE_ROMAN,i); */
rx += glutBitmapWidth(GLUT_BITMAP_9_BY_15,k);
//   rx += 10;

}

void display(void)
{
int shift=0;
glPushAttrib(GL_ALL_ATTRIB_BITS);
glClearColor (0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
screen_box(0,wh-ww/10,ww/10);
glColor3f(1.0, 0.0, 0.0);
screen_box(ww/10,wh-ww/10,ww/10);
glColor3f(0.0, 1.0, 0.0);
screen_box(ww/5,wh-ww/10,ww/10);
glColor3f(0.0, 0.0, 1.0);
screen_box(3*ww/10,wh-ww/10,ww/10);
glColor3f(1.0, 1.0, 0.0);
screen_box(2*ww/5,wh-ww/10,ww/10);
glColor3f(0.0, 0.0, 0.0);
screen_box(ww/10+ww/40,wh-ww/10+ww/40,ww/20);
glBegin(GL_LINES);
glVertex2i(wh/40,wh-ww/20);
glVertex2i(wh/40+ww/20,wh-ww/20);
glEnd();
glBegin(GL_TRIANGLES);
glVertex2i(ww/5+ww/40,wh-ww/10+ww/40);
glVertex2i(ww/5+ww/20,wh-ww/40);
glVertex2i(ww/5+3*ww/40,wh-ww/10+ww/40);
glEnd();
glPointSize(3.0);
glBegin(GL_POINTS);
glVertex2i(3*ww/10+ww/20, wh-ww/20);
glEnd();
glRasterPos2i(2*ww/5,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'A');
shift=glutBitmapWidth(GLUT_BITMAP_9_BY_15, 'A');
glRasterPos2i(2*ww/5+shift,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'B');
shift+=glutBitmapWidth(GLUT_BITMAP_9_BY_15, 'B');
glRasterPos2i(2*ww/5+shift,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'C');
glFlush();
glPopAttrib();
}

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

glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("paint");
glutDisplayFunc(display);
myinit ();
glutReshapeFunc (myReshape);
glutKeyboardFunc(key);
glutMouseFunc (mouse);
glutMainLoop();

return 0;

}

This produces the following screens:

And on drawing you may get an screen that looks like this one: