/* proj3.c */ /* CS4451 Project 3: Voronoi Diagrams */ /* James (Wervyn) Wert */ #include #include #include #include #include #include #include #include #define VPD_MIN 200 #define VPD_DEFAULT 800 #define VPD_MAX 1024 #define MENU_SHOW_SITES 1 #define MENU_SPRAY_POINTS 2 #define MENU_STOP_RUN 3 #define MENU_RANDOM_IMAGE 4 #define MENU_RESET 5 typedef struct { double r, g, b; } RGB; typedef struct { double x, y; double theta, dtheta; RGB color; } VCone; typedef struct { unsigned char r,g,b; } RGB_Char; typedef struct { int sizex, sizey; RGB_Char *color; } PPMImage; GLint wid, vpd = VPD_DEFAULT; GLuint coneID, siteID; GLint showsites = 1; GLint animate = 0; GLint fromimage = 0; PPMImage srcimage; VCone *sitelist; int numsites; double randomd() { return((double) rand()) / (RAND_MAX + 1.0); } GLvoid init_cone(VCone *cone) { cone->x = randomd() * 2 - 1; cone->y = randomd() * 2 - 1; cone->theta = 0; cone->dtheta = randomd()*10; cone->color.r = randomd(); cone->color.g = randomd(); cone->color.b = randomd(); } GLvoid create_lists() { coneID = glGenLists(1); siteID = glGenLists(1); glNewList(coneID, GL_COMPILE); glBegin(GL_TRIANGLE_FAN); glVertex4f(0.0, 0.0, 0.0, 1.0); for (int i = 0; i <= 360; i+=5) { glVertex4f(cos(i*M_PI/180), sin(i*M_PI/180), -1.0, 0.33); } glEnd(); glEndList(); glNewList(siteID, GL_COMPILE); glColor3d(0, 0, 0); glBegin(GL_TRIANGLE_FAN); glVertex4f(0.0, 0.0, 1.0, 1.0); for (int i = 0; i <= 360; i+=45) { glVertex4f(cos(i*M_PI/180), sin(i*M_PI/180), -1.0, 100.0); } glEnd(); glEndList(); } GLvoid draw() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1, 1, -1, 1, 0, 3); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glutSetWindow(wid); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (int i = 0; i < numsites; i++) { VCone *cone = &sitelist[i]; if (fromimage) { double tx, ty; int x, y, index; tx = (cone->x*cos(cone->theta*M_PI/180) - cone->y*sin(cone->theta*M_PI/180)); ty = (cone->x*sin(cone->theta*M_PI/180) + cone->y*cos(cone->theta*M_PI/180)); x = (int) ((tx + 1)/2 * srcimage.sizex); y = (int) (srcimage.sizey - (ty + 1)/2 * srcimage.sizey - 1); if (x < 0) x = 0; if (x >= srcimage.sizex) x = srcimage.sizex - 1; if (y < 0) y = 0; if (y >= srcimage.sizey) y = srcimage.sizey - 1; index = y * srcimage.sizey + x; glColor3d(srcimage.color[index].r/255.0, srcimage.color[index].g/255.0, srcimage.color[index].b/255.0); } else glColor3d(cone->color.r, cone->color.g, cone->color.b); glPushMatrix(); glRotated(cone->theta, 0.0, 0.0, 1.0); /* Lancer, here's the rotation */ glTranslated(cone->x, cone->y, -1.0); glCallList(coneID); if (showsites) glCallList(siteID); glPopMatrix(); if (animate) { cone->theta += cone->dtheta; if (cone->theta >= 360) cone->theta -= 360; } } glFlush(); glutSwapBuffers(); if (animate) glutPostRedisplay(); } GLvoid reset_simulation() { animate = 0; fromimage = 0; showsites = 1; numsites = 32; sitelist = (VCone *) malloc(numsites*sizeof(VCone)); if (sitelist == NULL) { free(srcimage.color); exit(1); } for (int i = 0; i < numsites; i++) { init_cone(&sitelist[i]); } } GLvoid spray_points() { sitelist = (VCone *) realloc(sitelist, numsites*2*sizeof(VCone)); if (sitelist == NULL) { exit(1); } for (int i = numsites; i < numsites*2; i++) { init_cone(&sitelist[i]); } numsites *= 2; } GLvoid keyboard(GLubyte key, GLint x, GLint y) { switch(key) { case 27: free(sitelist); free(srcimage.color); exit(0); default: break; } } GLvoid menu(int value) { switch(value) { case MENU_SHOW_SITES: showsites = !showsites; break; case MENU_SPRAY_POINTS: spray_points(); break; case MENU_STOP_RUN: animate = !animate; break; case MENU_RANDOM_IMAGE: fromimage = !fromimage; break; case MENU_RESET: free(sitelist); reset_simulation(); break; } glutPostRedisplay(); } GLvoid reshape(GLint vpw, GLint vph) { glutSetWindow(wid); if (vpw < vph) vpd = vph; else vpd = vpw; if (vpd < VPD_MIN) vpd = VPD_MIN; if (vpd > VPD_MAX) vpd = VPD_MAX; glViewport(0, 0, vpd, vpd); glutReshapeWindow(vpd, vpd); glutPostRedisplay(); } GLint init_glut(GLint *argc, char **argv) { GLint id; glutInit(argc,argv); glutInitWindowSize(vpd, vpd); glutInitWindowPosition(10,10); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); id = glutCreateWindow("cs4451 assignment 3: Voronoi Diagrams"); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutDisplayFunc(draw); GLint menuID = glutCreateMenu(menu); glutAddMenuEntry("Show Sites", MENU_SHOW_SITES); glutAddMenuEntry("Spray Sites", MENU_SPRAY_POINTS); glutAddMenuEntry("Animate", MENU_STOP_RUN); glutAddMenuEntry("Coloring Mode", MENU_RANDOM_IMAGE); glutAddMenuEntry("Reset", MENU_RESET); glutSetMenu(menuID); glutAttachMenu(GLUT_RIGHT_BUTTON); return id; } GLvoid init_opengl() { glShadeModel(GL_FLAT); glClearColor(0.0, 0.0, 0.0, 1.0); glEnable(GL_DEPTH_TEST); } PPMImage read_ppmimage(const char *name) { PPMImage result; int range; FILE *fp = fopen(name,"rb"); if (!fp) { fprintf(stderr,"No file\n"); exit(1); } assert(getc(fp) == 'P'); assert(getc(fp) == '6'); fscanf(fp, "%d%d%d\n", &result.sizex, &result.sizey, &range); assert(range == 255); result.color = (RGB_Char *) malloc(result.sizex*result.sizey*sizeof(RGB_Char)); fread(result.color,sizeof(RGB_Char),result.sizex*result.sizey,fp); return result; } GLint main(GLint argc, char **argv) { srand((unsigned) time(0)); if (argc > 1) srcimage = read_ppmimage(argv[1]); else { RGB_Char black; srcimage.sizex = srcimage.sizey = 1; srcimage.color = (RGB_Char *) malloc(sizeof(RGB_Char)); srcimage.color[0] = black; } reset_simulation(); wid = init_glut(&argc, argv); init_opengl(); create_lists(); glutMainLoop(); free(sitelist); free(srcimage.color); return 0; }