/* Assignment 1 - Duy Nguyen: September 12, 2006 * This program draws a grid and allows the user to draw lines and polygons. * It handles techniques to draw lines at the pixel level, as well as filling * polygons as required. * * Just to note, this program uses triangle.c as a template for many of the * Glut functions. */ #include #include #include /* // Sometimes glu.h includes glut.h--sometimes not. */ #ifdef MAC_OSX # include # include #else # include # include #endif typedef enum DQN_object { DQN_LINE, DQN_POLY } DQN_object; /* -------------------------------------------------------------------------- */ // Function Declarations static void display_CB(void); /* Called whenever redisplay needed */ static void key_CB(unsigned char key, int x, int y); /* Called on key press */ static void mouse_CB(int button, int state, int x, int y); /* Called on mouse click */ static void add_object_CB(int value); static void runCommand(char* s); /* Reads a line and adds it to the list of shapes */ static void drawGrid(); /* Draw grid */ static void drawLine(int x1, int y1, int x2, int y2); /* Draw a specified Line */ static void drawPoly(int* x, int* y, int size); /*Draw a specified Polygon */ static void fillPixel(int x, int y); //Fill a Pixel static void addLine(int x1, int y1, int x2, int y2); /*add line to current list*/ static void addPoly(int x, int y, int size); /*add polygon to current list*/ static void changeColor(); /* upgrade color*/ static void parseFile(); static void saveFile(); /* -------------------------------------------------------------------------- */ // Instance Variable Declarations static int first_x = -1; static int first_y = -1; //Current Colors static float cur_red = 1.0; static float cur_green = 1.0; static float cur_blue = 1.0; static int cellSize = 30; //Pixel size of cells static int gridWidth = 21; static int gridHeight = 21; static char commands[1000][500]; static int cmSize = 0; static int polyX[100]; static int polyY[100]; static int polySize = 0; static int colorSwitch = 0; static int mode = 0; /* 0 means line-draw mode, 1 means poly-draw mode */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { int win; int submenu; glutInit(&argc, argv); /* initialize GLUT system */ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(630, 630); win = glutCreateWindow("Assignment 1"); /* create window */ /* set background to black */ glClearColor((GLclampf)0.0,(GLclampf)0.0,(GLclampf)0.0,(GLclampf)0.0); gluOrtho2D(0.0, 630.0, 0.0, 630.0); /* how object is mapped to window */ glutDisplayFunc(display_CB); /* set window's display callback */ glutKeyboardFunc(key_CB); /* set window's key callback */ glutMouseFunc(mouse_CB); /* set window's mouse callback */ /* Create a menu which is accessed by the right button. */ glutCreateMenu(add_object_CB); glutAddMenuEntry("Line Mode", DQN_LINE); glutAddMenuEntry("Polygon Mode", DQN_POLY); glutAttachMenu(GLUT_RIGHT_BUTTON); parseFile(); // Read in any predone code glutMainLoop(); /* start processing events... */ /* Execution never reaches this point, so return value is failure */ return EXIT_FAILURE; } static void parseFile() { if(!isatty(fileno(stdin))) { char* temp[500]; while( fgets(temp, 500, stdin) != NULL) { strcpy(&commands[cmSize], temp); cmSize++; } } } static void saveFile() { int i = 0; for(i = 0; i < cmSize; i++) { printf("%s", commands[i]); } } static void runCommand(char* s) { const char delimiters[] = " "; char* token; char cp[500]; strcpy (cp, s); token = strtok (cp, delimiters); if( strcmp(token, "line") == 0) { glColor3d(.8, .8, .8); int a = atoi(strtok (NULL, delimiters)); int b = atoi(strtok (NULL, delimiters)); int c = atoi(strtok (NULL, delimiters)); int d = atoi(strtok (NULL, delimiters)); drawLine(a,b,c,d); } else if ( strcmp(token, "poly") == 0) { changeColor(); glColor3d(cur_red, cur_green, cur_blue); int xPol[100]; int yPol[100]; int pSize = 0; token = strtok(NULL, delimiters); while( token != NULL) { xPol[pSize] = atoi(token); yPol[pSize] = atoi(strtok(NULL, delimiters)); pSize++; token = strtok(NULL, delimiters); } drawPoly(xPol, yPol, pSize); } } // Draws a grid on the display static void drawGrid() { int i = 0; int j = 0; glColor3d(.7, .7, .7); //Set Color to Grey glBegin(GL_LINES); //Start Draw for( i = 0; i < gridWidth; i++) { for(j = 0; j < gridHeight; j++) { glVertex3f( i*cellSize, j*cellSize+(cellSize-1), 0); // Top Left glVertex3f( i*cellSize+(cellSize-1), j*cellSize+(cellSize-1), 0); // Top Right glVertex3f( i*cellSize+(cellSize-1), j*cellSize+(cellSize-1), 0); // Top Right glVertex3f( i*cellSize+(cellSize-1), j*cellSize, 0); // Bot Right glVertex3f( i*cellSize+(cellSize-1), j*cellSize, 0); // Bot Right glVertex3f( i*cellSize, j*cellSize, 0); // Bot Left glVertex3f( i*cellSize, j*cellSize, 0); // Bot Left glVertex3f( i*cellSize, j*cellSize+(cellSize-1), 0); // Top Left } } glEnd(); //End Draw } /* Draw a specified Line */ static void drawLine(int x1, int y1, int x2, int y2) { int x = x1; int y = y1; int xEnd = x2; int yEnd = y2; //Make sure we are always drawing from left to right if (x1 > x2) { x = x2; xEnd = x1; y = y2; yEnd = y1; } else if ( x1 == x2) { if( y1 < y2) { x = x2; xEnd = x1; y = y2; yEnd = y1; } } int dx = xEnd - x; int dy = yEnd - y; if(dx*dy > 0) //positive slope { if( dx >= dy) // Slope is between 1 and 0 { int p = 2*dy - dx; fillPixel(x,y); while( x != xEnd) { x++; if(p > 0) { y = y+1; fillPixel(x,y); p = p+2*dy-2*dx; } else { fillPixel(x,y); p = p+2*dy; } } } else //Slope is greater than 1 { int p = 2*dx - dy; fillPixel(x,y); while( y != yEnd) { y++; if(p > 0) { x = x+1; fillPixel(x,y); p = p+2*dx-2*dy; } else { fillPixel(x,y); p = p+2*dx; } } } } else //Negative slope { if( dx >= abs(dy)) //Flatter Slope { dy = abs(dy); int p = 2*dy - dx; fillPixel(x,y); while( x != xEnd) { x++; if(p > 0) { y = y-1; fillPixel(x,y); p = p+2*dy-2*dx; } else { fillPixel(x,y); p = p+2*dy; } } } else //Taller Slope { dy = abs(dy); int p = 2*dx - dy; fillPixel(x,y); while( y != yEnd) { y--; if(p > 0) { x = x+1; fillPixel(x,y); p = p+2*dx-2*dy; } else { fillPixel(x,y); p = p+2*dx; } } } } } //Draw a polygon static void drawPoly(int* x, int* y, int size) { int i; x[size] = x[0]; y[size] = x[0]; for(i = 0; i < size; i++) { int x1 = x[i]; int y1 = y[i]; int x2 = x[(i+1)%size]; int y2 = y[(i+1)%size]; drawLine(x1, y1, x2, y2); } //Find row min and row max int rMin = 20; int rMax = -20; for(i = 0; i < size; i++) { if(y[i] > rMax) rMax = y[i]; if(y[i] < rMin) rMin = y[i]; } int index = rMax - rMin +1; //Compile edge table int xA[index]; int xA_num[index]; int dxA[index]; int dyA[index]; int yA[index]; int xB[index]; int xB_num[index]; int dxB[index]; int dyB[index]; int yB[index]; for( i = 0; i < index; i++) { xA[i] = -999; xA_num[i]= -999; dxA[i]= -999; dyA[i]= -999; yA[i]= -999; xB[i]= -999; xB_num[i]= -999; dxB[i]= -999; dyB[i]= -999; yB[i]= -999; } //Look at each edge for(i = 0; i < size; i++) { int x1 = x[i]; int x2 = x[(i+1)%size]; int y1 = y[i]; int y2 = y[(i+1)%size]; //ignore horizontal lines if( y1 != y2) { if( y1 < y2) { //printf("hit\n"); if(dxA[i] == -999) { printf("%d\n", y1); xA[y1] = x1; xA_num[y1] = 0; dxA[y1] = x2-x1; dyA[y1] = y2-y1; yA[y1] = y2; } else { xB[y1] = x1; xB_num[y1] = 0; dxB[y1] = x2-x1; dyB[y1] = y2-y1; yB[y1] = y2; } } else { if(dxA[i] == -999) { xA[y2] = x2; xA_num[y2] = 0; dxA[y2] = x1-x2; dyA[y2] = y1-y2; yA[y2] = y1; } else { xB[y2] = x2; xB_num[y2] = 0; dxB[y2] = x1-x2; dyB[y2] = y1-y2; yB[y2] = y1; } } } } //Build Active Edge List //For Each Row for(i = 0; i < index; i ++) { if(dxA[i] != -999) { int nextY = i + 1; //If the next row is not max if( nextY < yA[i]) { //copy displacement and max dxA[nextY] = dxA[i]; dyA[nextY] = dyA[i]; yA[nextY] = yA[i]; //Calculate X's int x_int = xA[i]; int num = xA_num[i] + dxA[i]; if( num >= dyA[i]) { xA[nextY] = xA[i] + 1; num = num - dyA[i]; } xA_num[nextY] = num; } } if(dxB[i] != -999) { int nextY = i + 1; //If the next row is not max if( nextY < yB[i]) { //copy displacement and max dxB[nextY] = dxB[i]; dyB[nextY] = dyB[i]; yB[nextY] = yB[i]; //Calculate X's int x_int = xB[i]; int num = xB_num[i] + dxB[i]; if( num >= dyB[i]) { xB[nextY] = xB[i] + 1; num = num - dyB[i]; } xB_num[nextY] = num; } } } i = 0; //Fill in Active Edge List for(i = 0; i < index; i ++) { //printf("%d: %d %d\n", i, xA[i], xB[i]); } } static void fillPixel(int x, int y) { int x2 = x + 10; int y2 = y + 10; /* draw filled Square */ glBegin(GL_POLYGON); glVertex2i(x2*cellSize, y2*cellSize+(cellSize-1)); glVertex2i(x2*cellSize+(cellSize-1), y2*cellSize+(cellSize-1)); glVertex2i(x2*cellSize+(cellSize-1), y2*cellSize); glVertex2i(x2*cellSize, y2*cellSize); glEnd(); } static void changeColor() { if( colorSwitch == 0) { cur_red = 0.0; cur_green = 1.0; cur_blue = 0.0; colorSwitch++; } else if( colorSwitch == 1) { cur_red = 0.0; cur_green = 0.0; cur_blue = 1.0; colorSwitch++; } else if( colorSwitch == 2) { cur_red = 1.0; cur_green = 0.0; cur_blue = 1.0; colorSwitch++; } else if( colorSwitch == 3) { cur_red = 1.0; cur_green = 1.0; cur_blue = 0.0; colorSwitch++; } else if( colorSwitch == 4) { cur_red = 0.0; cur_green = 1.0; cur_blue = 1.0; colorSwitch = 0; } } /* /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ */ /* // Function called whenever redisplay needed (try hiding the window and then // exposing it. The debug macro should print something.) */ static void display_CB(void) { glClear(GL_COLOR_BUFFER_BIT); /* clear the display */ drawGrid(); colorSwitch = 0; int i = 0; for( i = 0; i < cmSize; i ++) { runCommand(commands[i]); } if( first_x != -1) { glColor3d(1.0, 0.0, 0.0); fillPixel(first_x, first_y); } if(polySize == 1) { glColor3d(1.0, 0.0, 0.0); fillPixel(polyX[0], polyY[0]); } for( i = 1; i < polySize; i++) { glColor3d(1.0, 0.0, 0.0); drawLine(polyX[i-1], polyY[i-1],polyX[i], polyY[i]); } glEnd(); /* OpenGL draws the filled triangle */ glFlush(); /* Complete any pending operations */ glutSwapBuffers(); /* Make the drawing buffer the frame buffer and vice versa */ } /* /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ */ /* Function called on key press */ static void key_CB(unsigned char key, int x, int y) { if( key == 'q' ) { saveFile(); exit(0); } else if( key == 'u' ) { cmSize--; display_CB(); } else if( key == 'c' ) { cmSize=0; display_CB(); } else display_CB(); } /* /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ */ /* Function called on mouse click */ static void mouse_CB(int button, int state, int x, int y) { if (button == 0) { if (state == 0) { display_CB(); } else if (state == 1) { if( mode == 0) { glColor3d(1.0, 0.0, 0.0); if( first_x == -1) { first_x = ((x - (x % cellSize))/cellSize) - 10; first_y = -(((y - (y % cellSize))/cellSize) - 10); fillPixel(first_x, first_y); } else { int sec_x = ((x - (x % cellSize))/cellSize) - 10; int sec_y = -(((y - (y % cellSize))/cellSize) - 10); sprintf(commands[cmSize], "line %d %d %d %d\n", first_x, first_y, sec_x, sec_y); cmSize++; first_x = -1; } } else { int xTemp = ((x - (x % cellSize))/cellSize) - 10; int yTemp = -(((y - (y % cellSize))/cellSize) - 10); if(polySize > 0) { if((xTemp == polyX[0]) && (yTemp == polyY[0])) { char buff[500]; sprintf(buff, "%s", "poly"); int i = 0; for( i = 0; i < polySize; i++) { sprintf(buff, "%s %d %d", buff, polyX[i], polyY[i]); } polySize = 0; sprintf(buff, "%s\n", buff); strcpy(commands[cmSize], buff); cmSize++; } else { polyX[polySize] = xTemp; polyY[polySize] = yTemp; polySize++; } } else { polyX[polySize] = xTemp; polyY[polySize] = yTemp; polySize++; } } display_CB(); } } } /* /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ */ static void add_object_CB(int value) { if (value == DQN_LINE) { mode = 0; } else if (value == DQN_POLY) { mode = 1; } }