/* lineblend.c * * To compile: cc -o lineblend lineblend.c -lGL -lGLU -lX11 -lglut -lXmu * * Usage: lineblend * * This is an puffed up version of the first GL assignment we had for my * graphics class: write a 2-d openGL program w/ color and interactivity. * * Left and middle buttons drawn colored lines, right button brings up a menu * with a few options. If you draw for long enough and then hit pick * "redraw" (or resize or uncover the window) it takes so long to redraw * all the lines it is kind of like a kaleidoscope animation. Or something. * * Philip Winston - 2/11/95 (modified: 2/12) * pwinston@hmc.edu * http://www.cs.hmc.edu/people/pwinston * */ #include #include #include #ifdef _WIN32 #define drand48() (((float) rand())/((float) RAND_MAX)) #endif typedef enum {MENU_ALPHA_1, MENU_ALPHA_2, MENU_ALPHA_3, MENU_ALPHA_4, MENU_COLOR_1, MENU_COLOR_2, MENU_COLOR_3, MENU_COLOR_4, MENU_ANTI_ON, MENU_ANTI_OFF, MENU_ERASE, MENU_REDRAW, MENU_QUIT} MenuChoices; typedef enum {SC1, SC2, SC3, SC4} ColorScheme; int wwidth, wheight, downbtn = -1, downx, downy; GLuint DispLists = 1; GLfloat Alpha = 0.2; int Color = SC1; void myglInit(void) { glLineWidth(10.0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-0.5,0.5,-0.5,0.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glFlush(); } void myreshape(GLsizei w, GLsizei h) { wwidth = w; wheight = h; glViewport(0,0,w,h); glClear(GL_COLOR_BUFFER_BIT); glFlush(); } void mydisplay(void) { GLuint i; glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < DispLists; i++) glCallList(i); glFlush(); } void drawline(int x, int y) { GLfloat fx = (float)(x - downx)/wwidth, fy = -((float)(y - downy)/wheight), r1, g1, b1, r2, g2, b2; switch(Color) { /* four different ways to pick colors */ case SC1: /* just kind of random formulas... */ r1 = fy+1; g1 = 0; b1 = (float)x/wwidth; r2 = 0; g2 = fy+1; b2 = 1-(float)x/wwidth; break; case SC2: r1 = fx+fy+1; g1 = 0; b1 = 0; r2 = 0; g2 = fx+fy+1; b2 = 0; break; case SC3: r1 = 0; g1 = (float)downx/wwidth; b1 = (float)x/wwidth; r2 = 0; g2 = (float)y/wheight; b2 = (float)downy/wheight; break; case SC4: r1 = drand48(); g1 = drand48(); b1 = (float)downx/(wwidth*1.5); r2 = drand48(); g2 = (float)downy/(wheight*1.5); b2 = drand48(); break; } glBegin(GL_LINES); glColor4f(r1, g1, b1, Alpha); switch(downbtn) { case GLUT_LEFT_BUTTON: glVertex2f(0,0); break; case GLUT_MIDDLE_BUTTON: glVertex2f(-fx,-fy); break; } glColor4f(r2, g2, b2, Alpha); glVertex2f(fx,fy); glEnd(); glFlush(); } void mousebutton(int btn, int state, int x, int y) { GLfloat fx = (float)x/wwidth - 0.5, fy = -(float)y/wheight + 0.5; if (state == GLUT_DOWN && downbtn == -1) { glNewList(DispLists++, GL_COMPILE_AND_EXECUTE); glPushMatrix(); glTranslatef(fx, fy, 0); downbtn = btn; downx = x; downy = y; drawline(x, y); } else if (state == GLUT_UP && btn == downbtn) { glPopMatrix(); glEndList(); downbtn = -1; } } /* * For some reason I felt like doing these check boxes -- it is kind of * lame the way I did it, though. Probably a smarter and easier way. */ void handlealphamenu(int value) { glutChangeToMenuEntry(1,"[ ] 0.05", MENU_ALPHA_1); glutChangeToMenuEntry(2,"[ ] 0.20", MENU_ALPHA_2); glutChangeToMenuEntry(3,"[ ] 0.50", MENU_ALPHA_3); glutChangeToMenuEntry(4,"[ ] 1.00", MENU_ALPHA_4); switch (value) { case MENU_ALPHA_1: glutChangeToMenuEntry(1, "[ * ] 0.05", MENU_ALPHA_1); Alpha = 0.05; break; case MENU_ALPHA_2: glutChangeToMenuEntry(2, "[ * ] 0.20", MENU_ALPHA_2); Alpha = 0.2; break; case MENU_ALPHA_3: glutChangeToMenuEntry(3, "[ * ] 0.50", MENU_ALPHA_3); Alpha = 0.5; break; case MENU_ALPHA_4: glutChangeToMenuEntry(4, "[ * ] 1.00", MENU_ALPHA_4); Alpha = 1.0; break; } } void handlecolormenu(int value) { glutChangeToMenuEntry(1,"[ ] Various", MENU_COLOR_1); glutChangeToMenuEntry(2,"[ ] Red/Green ", MENU_COLOR_2); glutChangeToMenuEntry(3,"[ ] Blue/Green", MENU_COLOR_3); glutChangeToMenuEntry(4,"[ ] Random", MENU_COLOR_4); switch (value) { case MENU_COLOR_1: glutChangeToMenuEntry(1, "[ * ] Various", MENU_COLOR_1); Color = SC1; break; case MENU_COLOR_2: glutChangeToMenuEntry(2, "[ * ] Red/Green", MENU_COLOR_2); Color = SC2; break; case MENU_COLOR_3: glutChangeToMenuEntry(3, "[ * ] Blue/Green", MENU_COLOR_3); Color = SC3; break; case MENU_COLOR_4: glutChangeToMenuEntry(4, "[ * ] Random", MENU_COLOR_4); Color = SC4; break; } } void handlemenu(int value) { switch (value) { case MENU_ANTI_OFF: glDisable(GL_LINE_SMOOTH); glutChangeToMenuEntry(3, "anti-aliasing [NO]", MENU_ANTI_ON); break; case MENU_ANTI_ON: glEnable(GL_LINE_SMOOTH); glutChangeToMenuEntry(3, "anti-aliasing [YES]", MENU_ANTI_OFF); break; case MENU_REDRAW: glutPostRedisplay(); break; case MENU_ERASE: glDeleteLists(0, DispLists); DispLists = 1; mydisplay(); break; case MENU_QUIT: exit(0); break; } } void myMenuInit(void) { int sub1,sub2,sub3; sub3 = glutCreateMenu(handlealphamenu); glutAddMenuEntry("[ ] 0.05", MENU_ALPHA_1); glutAddMenuEntry("[ * ] 0.20", MENU_ALPHA_2); glutAddMenuEntry("[ ] 0.50", MENU_ALPHA_3); glutAddMenuEntry("[ ] 1.00", MENU_ALPHA_4); sub2 = glutCreateMenu(handlecolormenu); glutAddMenuEntry("[ * ] Various", MENU_COLOR_1); glutAddMenuEntry("[ ] Red/Green", MENU_COLOR_2); glutAddMenuEntry("[ ] Blue/Green", MENU_COLOR_3); glutAddMenuEntry("[ ] Random", MENU_COLOR_4); sub1 = glutCreateMenu(handlemenu); glutAddSubMenu("Colors", sub2); glutAddSubMenu("Alpha", sub3); glutAddMenuEntry("anti-aliasing [NO]", MENU_ANTI_ON); glutCreateMenu(handlemenu); glutAddSubMenu("Lines", sub1); glutAddMenuEntry("Erase", MENU_ERASE); glutAddMenuEntry("Redraw", MENU_REDRAW); glutAddMenuEntry("Quit", MENU_QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(512, 512); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutCreateWindow("lineblend"); myglInit(); myMenuInit(); glutReshapeFunc(myreshape); glutMouseFunc(mousebutton); glutMotionFunc(drawline); glutDisplayFunc(mydisplay); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }