/* $Id: tessdemo.c,v 1.8 2000/07/11 14:11:58 brianp Exp $ */ /* * A demo of the GLU polygon tesselation functions written by Bogdan Sikorski. */ #include #include #include #include #define MAX_POINTS 200 #define MAX_CONTOURS 50 static int menu; typedef enum { QUIT, TESSELATE, CLEAR } menu_entries; typedef enum { DEFINE, TESSELATED } mode_type; struct { GLint p[MAX_POINTS][2]; GLuint point_cnt; } contours[MAX_CONTOURS]; static GLuint contour_cnt; static GLsizei width, height; static mode_type mode; struct { GLsizei no; GLfloat color[3]; GLint p[3][2]; GLclampf p_color[3][3]; } triangle; static void GLCALLBACK my_error(GLenum err) { int len, i; char const *str; glColor3f(0.9, 0.9, 0.9); glRasterPos2i(5, 5); str = (const char *) gluErrorString(err); len = strlen(str); for (i = 0; i < len; i++) glutBitmapCharacter(GLUT_BITMAP_9_BY_15, str[i]); } static void GLCALLBACK begin_callback(GLenum mode) { triangle.no = 0; } static void GLCALLBACK edge_callback(GLenum flag) { if (flag == GL_TRUE) { triangle.color[0] = 1.0; triangle.color[1] = 1.0; triangle.color[2] = 0.5; } else { triangle.color[0] = 1.0; triangle.color[1] = 0.0; triangle.color[2] = 0.0; } } static void GLCALLBACK end_callback() { glBegin(GL_LINES); glColor3f(triangle.p_color[0][0], triangle.p_color[0][1], triangle.p_color[0][2]); glVertex2i(triangle.p[0][0], triangle.p[0][1]); glVertex2i(triangle.p[1][0], triangle.p[1][1]); glColor3f(triangle.p_color[1][0], triangle.p_color[1][1], triangle.p_color[1][2]); glVertex2i(triangle.p[1][0], triangle.p[1][1]); glVertex2i(triangle.p[2][0], triangle.p[2][1]); glColor3f(triangle.p_color[2][0], triangle.p_color[2][1], triangle.p_color[2][2]); glVertex2i(triangle.p[2][0], triangle.p[2][1]); glVertex2i(triangle.p[0][0], triangle.p[0][1]); glEnd(); } static void GLCALLBACK vertex_callback(void *data) { GLsizei no; GLint *p; p = (GLint *) data; no = triangle.no; triangle.p[no][0] = p[0]; triangle.p[no][1] = p[1]; triangle.p_color[no][0] = triangle.color[0]; triangle.p_color[no][1] = triangle.color[1]; triangle.p_color[no][2] = triangle.color[2]; ++(triangle.no); } static void set_screen_wh(GLsizei w, GLsizei h) { width = w; height = h; } static void tesse(void) { GLUtriangulatorObj *tobj; GLdouble data[3]; GLuint i, j, point_cnt; tobj = gluNewTess(); if (tobj != NULL) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.7, 0.7, 0.0); gluTessCallback(tobj, GLU_BEGIN, glBegin); gluTessCallback(tobj, GLU_END, glEnd); gluTessCallback(tobj, GLU_ERROR, my_error); gluTessCallback(tobj, GLU_VERTEX, glVertex2iv); gluBeginPolygon(tobj); for (j = 0; j <= contour_cnt; j++) { point_cnt = contours[j].point_cnt; gluNextContour(tobj, GLU_UNKNOWN); for (i = 0; i < point_cnt; i++) { data[0] = (GLdouble) (contours[j].p[i][0]); data[1] = (GLdouble) (contours[j].p[i][1]); data[2] = 0.0; gluTessVertex(tobj, data, contours[j].p[i]); } } gluEndPolygon(tobj); glLineWidth(2.0); gluTessCallback(tobj, GLU_BEGIN, begin_callback); gluTessCallback(tobj, GLU_END, end_callback); gluTessCallback(tobj, GLU_VERTEX, vertex_callback); gluTessCallback(tobj, GLU_EDGE_FLAG, edge_callback); gluBeginPolygon(tobj); for (j = 0; j <= contour_cnt; j++) { point_cnt = contours[j].point_cnt; gluNextContour(tobj, GLU_UNKNOWN); for (i = 0; i < point_cnt; i++) { data[0] = (GLdouble) (contours[j].p[i][0]); data[1] = (GLdouble) (contours[j].p[i][1]); data[2] = 0.0; gluTessVertex(tobj, data, contours[j].p[i]); } } gluEndPolygon(tobj); gluDeleteTess(tobj); glutMouseFunc(NULL); glColor3f(1.0, 1.0, 0.0); glLineWidth(1.0); mode = TESSELATED; } } static void left_down(int x1, int y1) { GLint P[2]; GLuint point_cnt; /* translate GLUT into GL coordinates */ P[0] = x1; P[1] = height - y1; point_cnt = contours[contour_cnt].point_cnt; contours[contour_cnt].p[point_cnt][0] = P[0]; contours[contour_cnt].p[point_cnt][1] = P[1]; glBegin(GL_LINES); if (point_cnt) { glVertex2iv(contours[contour_cnt].p[point_cnt - 1]); glVertex2iv(P); } else { glVertex2iv(P); glVertex2iv(P); } glEnd(); glFinish(); ++(contours[contour_cnt].point_cnt); } static void middle_down(int x1, int y1) { GLuint point_cnt; point_cnt = contours[contour_cnt].point_cnt; if (point_cnt > 2) { glBegin(GL_LINES); glVertex2iv(contours[contour_cnt].p[0]); glVertex2iv(contours[contour_cnt].p[point_cnt - 1]); contours[contour_cnt].p[point_cnt][0] = -1; glEnd(); glFinish(); contour_cnt++; contours[contour_cnt].point_cnt = 0; } } static void mouse_clicked(int button, int state, int x, int y) { x -= x % 10; y -= y % 10; switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) left_down(x, y); break; case GLUT_MIDDLE_BUTTON: if (state == GLUT_DOWN) middle_down(x, y); break; } } static void display(void) { GLuint i, j; GLuint point_cnt; glClear(GL_COLOR_BUFFER_BIT); switch (mode) { case DEFINE: /* draw grid */ glColor3f(0.6, 0.5, 0.5); glBegin(GL_LINES); for (i = 0; i < width; i += 10) for (j = 0; j < height; j += 10) { glVertex2i(0, j); glVertex2i(width, j); glVertex2i(i, height); glVertex2i(i, 0); } glEnd(); glColor3f(1.0, 1.0, 0.0); for (i = 0; i <= contour_cnt; i++) { point_cnt = contours[i].point_cnt; glBegin(GL_LINES); switch (point_cnt) { case 0: break; case 1: glVertex2iv(contours[i].p[0]); glVertex2iv(contours[i].p[0]); break; case 2: glVertex2iv(contours[i].p[0]); glVertex2iv(contours[i].p[1]); break; default: --point_cnt; for (j = 0; j < point_cnt; j++) { glVertex2iv(contours[i].p[j]); glVertex2iv(contours[i].p[j + 1]); } if (contours[i].p[j + 1][0] == -1) { glVertex2iv(contours[i].p[0]); glVertex2iv(contours[i].p[j]); } break; } glEnd(); } glFinish(); break; case TESSELATED: /* draw lines */ tesse(); break; } glColor3f(1.0, 1.0, 0.0); } static void clear(void) { contour_cnt = 0; contours[0].point_cnt = 0; glutMouseFunc(mouse_clicked); mode = DEFINE; display(); } static void quit(void) { exit(0); } static void menu_selected(int entry) { switch (entry) { case CLEAR: clear(); break; case TESSELATE: tesse(); break; case QUIT: quit(); break; } } static void key_pressed(unsigned char key, int x, int y) { switch (key) { case 't': case 'T': tesse(); glFinish(); break; case 'q': case 'Q': quit(); break; case 'c': case 'C': clear(); break; } } static void myinit(void) { /* clear background to gray */ glClearColor(0.4, 0.4, 0.4, 0.0); glShadeModel(GL_FLAT); menu = glutCreateMenu(menu_selected); glutAddMenuEntry("clear", CLEAR); glutAddMenuEntry("tesselate", TESSELATE); glutAddMenuEntry("quit", QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMouseFunc(mouse_clicked); glutKeyboardFunc(key_pressed); contour_cnt = 0; glPolygonMode(GL_FRONT, GL_FILL); mode = DEFINE; } static void reshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, (GLdouble) w, 0.0, (GLdouble) h, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); set_screen_wh(w, h); } static void usage(void) { printf("Use left mouse button to place vertices.\n"); printf("Press middle mouse button when done.\n"); printf("Select tesselate from the pop-up menu.\n"); } /* Main Loop * Open window with initial window size, title bar, * RGBA display mode, and handle input events. */ int main(int argc, char **argv) { usage(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(400, 400); glutCreateWindow(argv[0]); myinit(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }