| lines2.c |
| /* ** Includes */ #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> #include <stdio.h> #include <stdlib.h> #include <math.h> /* ** TYPE DECLARATIONS */ /* ** this a record structure that contains two GL integers. */ typedef struct { GLint x, y; } GLintPoint; /* ** ... and this is a record of three GL floats (reals) for colour. ** r, g, and b can have the real values between 0 and 1. */ typedef struct { GLfloat r, g, b; } GLfloatRGBColour; /* ** We define a structure to store an array of points ** ** <Variable>.num == the number of points stored ** <Variable>.pt[0] == the first point in the list (if any) ** <Variable>.pt[0].x == the x-coord of the first point in the list (if any) */ #define ARRAY_MAX_NUM 10 typedef struct { int num; GLintPoint pt[ARRAY_MAX_NUM]; } GLintPointArray; /* ** Data structure for Linked List of Points ** ** It contains two fields: ** <Variable>.point (which has two fields itself -- .x, and .y) ** <Variable>.next */ typedef struct _GLintPointPtr { GLintPoint point; struct _GLintPointPtr *next; } GLintPointPtr; /* ** GLOBAL VARIABLES */ // windowHeight is used for 'flipping' the y-position. GLint windowHeight; GLint windowWidth; // We will be collecting a list of points, to draw lines between. // We initialise it so that poly.num == 0. GLintPointArray poly = {0}; // This will be our linked list of points GLintPointPtr *points; // We'll set the 'penColour' to 0 (black) int penColour = 0; // This is a list of 8 colours (Black -> White) // example use: setColour(colour[3]); GLfloatRGBColour colour[8] = { {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}}; /* ** FUNCTION HEADERS */ /* utility functions for setting up the window */ void setWindow (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top); void setViewport(GLint left, GLint right, GLint bottom, GLint top); /* utility drawing functions */ void clearScreen(void); void showScreen(void); void setPenColour(GLfloatRGBColour newColour); void setPenSize(int size); void drawPoint(GLint x, GLint y); void drawLine(GLint x1, GLint y1, GLint x2, GLint y2); /* utility functions for using polylines */ void drawPolyLine(GLintPointArray poly, int closed); void drawPolyLineFile(char * filename); /* utility functions for using linked lists */ GLintPointPtr* clearPoints(GLintPointPtr* points); void clearPoints2(GLintPointPtr* *points); void clearPoints3(GLintPointPtr* *points); /* callback functions */ void myDisplay(void); void myMouse(int button, int state, int x, int y); void myKeyboard(unsigned char theKey, int mouseX, int mouseY); void myReshape(GLsizei W, GLsizei H); void myInit(void); int main (int argc, char** argv); /* ** UTILITY FUNCTIONS */ /* set up the world view (2d - Orthographic) */ void setWindow(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(left, right, bottom, top); } /* set up the viewing window */ void setViewport(GLint left, GLint right, GLint bottom, GLint top) { glViewport(left, bottom, right - left, top - bottom); } void clearScreen(void) { glClear(GL_COLOR_BUFFER_BIT); } void showScreen(void) { glFlush(); } void setPenColour(GLfloatRGBColour newColour) { glColor3f(newColour.r, newColour.g, newColour.b); } void setPenSize(int size) { glPointSize(size); } void drawPoint(GLint x, GLint y) { glBegin(GL_POINTS); glVertex2i(x, y); glEnd(); } void drawLine(GLint x1, GLint y1, GLint x2, GLint y2) { glBegin(GL_LINES); glVertex2i(x1, y1); glVertex2i(x2, y2); glEnd(); } /* ** POLYLINE DRAWING FUNCTIONS */ void drawPolyLine(GLintPointArray poly, int closed) { int i; glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP); for (i = 0; i < poly.num; i++) glVertex2i(poly.pt[i].x, poly.pt[i].y); glEnd(); } /* ** The C version to read a file of lines ** ** NOTE: This is *not* good code!! (Not robust) */ void drawPolyLineFile(char * filename) { int i, j, numpolys, numlines; GLint x, y; char* line; FILE *inputFile; if ((inputFile = fopen(filename, "r")) == NULL) // Can't open the file!! { printf("\n\nCannot open the requested file '%s'\n\n", filename); printf("Program exiting"); exit(1); } // We read a string (upto 10 characters) from the file, and make it an int fgets(line, 10, inputFile); numpolys = atoi(line); for (j = 0; j < numpolys; j++) { fgets(line, 10, inputFile); numlines = atoi(line); glBegin(GL_LINE_STRIP); for (i = 0; i < numlines; i++) { fgets(line, 10, inputFile); sscanf(line, "%d %d", &x, &y); // scans the string 'line' for two ints glVertex2i(x,y); } glEnd(); } fclose(inputFile); showScreen(); } /* The C++ Version of drawing from the file ** ** NOTE: This is *not* good code!! (Not robust) ** needs the extra include: ** ** #include <fstream.h> ** * / void drawPolyLineFile(char * filename) { fstream inStream; inStream.open(filename, ios ::in); if (inStream.fail()) return; GLint numpolys, numlines, x, y; inStream >> numpolys; for (int j = 0; j < numpolys; j++) { inStream>> numlines; glBegin(GL_LINE_STRIP); for (int i = 0; i < numlines; i++) { inStream >> x >> y; glVertex2i(x,y); } glEnd(); } inStream.close(); showScreen(); } /* End of the C++ version */ /* ** ------------------------ ** Routines for Linked List ** ------------------------ */ /* ** Remove all the points in the list, and free up the space ** ** This is the first attempt, must be called like: ** points = clearPoints(points); ** */ GLintPointPtr* clearPoints(GLintPointPtr* points) { GLintPointPtr *tempptr; while (points != NULL) { tempptr = points; points = points->next; free(tempptr); } return NULL; } /* ** Remove all the points in the list, and free up the space ** ** This is the second attempt, as above, except it uses pass by ** reference rather than pass by value, it must be called like: ** clearPoints2(&points); ** */ void clearPoints2(GLintPointPtr* *points) { GLintPointPtr **tempptr; while (*points != NULL) { *tempptr = *points; *points = (*points)->next; free(*tempptr); } } /* ** Remove all the points in the list, and free up the space ** ** This is the third attempt, as above, except it uses recursion ** to free the list. Note that free() does not make the value NULL ** so we must do that ourselves (why don't we above :). ** clearPoints3(&points); ** */ void clearPoints3(GLintPointPtr* *points) { if (*points == NULL) return; clearPoints3(& ((*points)->next) ); free(*points); *points = NULL; } /* ** Main Drawing Routine */ void myDisplay(void) { clearScreen(); drawPolyLine(poly, 0); showScreen(); } /* ** LISTENERS */ /* ** Mouse Listener */ void myMouse(int button, int state, int x, int y) { // if we click the LEFT button - keep a track of the points. if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { // This is just for diagnostics !! // // %d == print the corresponding value as an integer. // \n == print 'end of line' // printf("Clicked on point (%d, %d)\n", x, windowHeight - y - 1); if (poly.num >= ARRAY_MAX_NUM) // Too many points for the array! { printf("TOO MANY POINTS!!\n"); return; } poly.pt[poly.num].x = x; poly.pt[poly.num].y = windowHeight - y - 1; poly.num++; drawPolyLine(poly, 0); } else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) { drawPolyLine(poly, 1); } } /* ** Key Listener */ void myKeyboard(unsigned char theKey, int mouseX, int mouseY) { mouseY = windowHeight - mouseY - 1; switch (theKey) { // if we type a 'c' - cycle through the 7 visible colours case 'c': case 'C': penColour = (++penColour)%7; setPenColour(colour[penColour]); break; // if we type a 'd' - draw the polyline case 'd': case 'D': drawPolyLine(poly, 0); break; // if we type an 'e' - erase the list of points case 'e': case 'E': poly.num = 0; break; // if we type an 'f' - draw the file case 'f': case 'F': drawPolyLineFile("polydata.txt"); break; // if we type an 'r' - refresh the screen case 'r': case 'R': myDisplay(); break; // if we type a 'w' - clear the screen case 'w': case 'W': clearScreen(); showScreen(); break; // if we type a 'q' - quit the program case 'q': case 'Q': exit(0); // otherwise - we don't have anything to do. default: break; } } /* ** Listener for reshaping the window */ void myReshape(GLsizei W, GLsizei H) { windowWidth = W; windowHeight = H; setWindow (0.0, windowWidth, 0.0, windowHeight); setViewport(0, windowWidth, 0, windowHeight); } /* ** INITIALISERS */ void myInit(void) { // Here's something to work out the size of the computer screen // and the size of the window we've created. float screenWidth, screenHeight; screenWidth = glutGet(GLUT_SCREEN_WIDTH); screenHeight = glutGet(GLUT_SCREEN_HEIGHT); windowWidth = glutGet(GLUT_WINDOW_WIDTH); windowHeight = glutGet(GLUT_WINDOW_HEIGHT); printf("\nInitial values are: Screen (%.1f, %.1f) && Window (%.1f, %.1f)\n", screenWidth, screenHeight, windowWidth, windowHeight); // now let's return to what we want to do.. // The 'usual' initialisation.. glClearColor(1.0, 1.0, 1.0, 0.0); glColor3f(0.0f, 0.0f, 0.0f); setPenSize(2.0); // ..and for what we're doing, we want the Viewport to match the World Window setWindow (0.0, windowWidth, 0.0, windowHeight); setViewport(0, (GLint) windowWidth, 0, (GLint) windowHeight); } /* ** MAIN */ int main (int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(640, 480); glutInitWindowPosition(100, 150); glutCreateWindow("Lines - type q to QUIT"); glutDisplayFunc(myDisplay); glutMouseFunc(myMouse); glutKeyboardFunc(myKeyboard); myInit(); glutMainLoop(); } |
| James Little |