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 doubles. */ typedef struct { GLdouble x, y; } GLPoint; /* ** ... 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; GLPoint pt[ARRAY_MAX_NUM]; } GLPointArray; /* ** 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 _GLPointPtr { GLPoint point; struct _GLPointPtr *next; } GLPointPtr; /* ** 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. GLPointArray poly = {0}; // This will be our linked list of points GLPointPtr *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(GLfloat size); void drawPoint(GLdouble x, GLdouble y); void drawLine(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); /* utility functions for using polylines */ void drawPolyLine(GLPointArray poly, int closed); void drawPolyLineFile(char * filename); /* utility functions for using linked lists */ GLPointPtr* clearPoints(GLPointPtr* points); void clearPoints2(GLPointPtr* *points); void clearPoints3(GLPointPtr* *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(GLfloat size) { glPointSize(size); glLineWidth(size); } void drawPoint(GLdouble x, GLdouble y) { glBegin(GL_POINTS); glVertex2d(x, y); glEnd(); } void drawLine(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) { glBegin(GL_LINES); glVertex2d(x1, y1); glVertex2d(x2, y2); glEnd(); } /* ** POLYLINE DRAWING FUNCTION */ void drawPolyLine(GLPointArray poly, int closed) { int i; glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP); for (i = 0; i < poly.num; i++) glVertex2d(poly.pt[i].x, poly.pt[i].y); glEnd(); } /* ** ------------------------ ** 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); ** */ GLPointPtr* clearPoints(GLPointPtr* points) { GLPointPtr *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(GLPointPtr* *points) { GLPointPtr **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(GLPointPtr* *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; clearPoints3(&points); 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 |