//Convert to malloc memory management /* ** Newsample: ** ** Usage: ** sample ** sample xsize ysize ** where xsize, ysize are size of window (max size 1024 by 768) ** (default 200 by 200) ** ** This program shows 2 styles of dynamic memory allocation for ** an OpenGL/GLUT application: ** ** (i) A dynamic 2D array, which represents the graphics window. ** This array duplicates all the RGB information that is seen in the OpenGL ** window. It would save some memory to only use OpenGL's window for this ** information, with no great drawback in efficiency. However, for some ** applications, there would be a price in speed, since the network would ** have to be accessed every time one wanted information about the value ** at some pixel (expensive for image processing applications). ** ** (ii) There is also a dynamically-allocated linked list. Every time the user ** samples a pixel with the mouse and left button, the coordinate and ** pixel colour at that coord in the image is stored. The point is plotted ** as a 2x2 square as well. When the user exits, this list of sampled ** coords and RGB values is dumped to a file. ** ** Copyright (2001) Anthony G. Gualtieri (revised by Brian J. Ross) */ #if !defined(Linux) #include //Not Linux must be windows #endif #include #include #include #include #include #include #include "newsample.h" /* ** display ** ** This is the callback function that displays the image in a window. ** First the 2D image of the window is dumped out pixel-by-pixel. ** Then the plotted points are written. */ void display() { int x,y; glClear(GL_COLOR_BUFFER_BIT); /* not really necessary, since whole window is replotted anyway */ glPointSize(2.0); // This helps take care of roundoff errors. glBegin(GL_POINTS); for (y=0; y < global.ySize; y++) { for (x=0; x < global.xSize; x++) { //glVertex2i(x,y); glVertex2f((float)x, (float)y); glColor3ub((GLbyte) global.theImage[x][y].red, (GLbyte) global.theImage[x][y].green, (GLbyte) global.theImage[x][y].blue); } } glEnd(); glFlush(); plot_previous_points(); /* draw sampled points */ } /* ** ** mouse: ** ** This is the function which samples points. ** Left click to generate a random colour at the point and add it ** to list of points sampled (so long as that point hasn't been sampled ** previously). ** ** ** btn - the button pressed ** state - the up or down state of the button ** x - the x co-ordinate of the sample point ** y - the y co-ordinate of the sample point ** */ void mouse(int btn, int state, int x, int y) { int yy; yy = glutGet(GLUT_WINDOW_HEIGHT); y = yy - y; /* In , Y coordinate increases from top to bottom */ if (state==GLUT_DOWN && btn==GLUT_LEFT_BUTTON) { if (check_duplicates(x,y) == FALSE) { glPointSize(3.0); glColor3f(0.0, 0.0, 0.0); glBegin(GL_POINTS); glVertex2i(x-1, y-1); //offset because pointsize=3 glEnd(); glFlush(); fprintf(stdout,"ADDED POINT %d: x=%3d y=%3d red: %3hd grn: %3hd blue: %3hd \n", ++global.numPtsAdded,x,y, global.theImage[x][y].red, global.theImage[x][y].green, global.theImage[x][y].blue); store_points(x,y, global.theImage[x][y].red, global.theImage[x][y].green, global.theImage[x][y].blue); } else fprintf(stdout, "The point has already been sampled. Try another.\n"); } } /* ** check_duplicates: ** ** This function ckecks if a sampled point has already been sampled and ** disallows it if it has. ** ** x - the x co-ordinate of the sampled point ** y - the y coordinate ** */ int check_duplicates(int x, int y){ dot *traverse=global.head; /* get ready to parse */ int result=FALSE; if (traverse == NULL) { /* empty list ? */ return FALSE; } else while (traverse != NULL) { if (x == (*traverse).x && y== (*traverse).y){ result = TRUE; break; } traverse = (*traverse).next; } return result; } /* ** store_point: ** ** Store a new point in the linked list of sampled points. ** ** x, y - coordinates of sampled poind ** r,g,b - RGB colour to store ** */ void store_points(int x, int y, int red, int grn, int blue) { dot * newPoint = (dot*) malloc (sizeof(dot)); newPoint->x = x; newPoint->y = y; newPoint->red = red; newPoint->green = grn; newPoint->blue = blue; newPoint->next = NULL; add_point(newPoint); } /* ** add_point: ** ** This is the function which actually does the work of putting the sampled ** point onto the linked list of previously sampled and read-in points. ** ** newPoint - a pointer to a 'dot' structure ** */ void add_point(dot *newPoint) { if (global.head != NULL) { /* non-empty list -- add it */ (*global.tail).next = newPoint; (*newPoint).next = NULL; global.tail = newPoint; } else { /* empty list -- 1st item */ global.head = newPoint; global.tail = newPoint; (*newPoint).next = NULL; } } /* ** writeout: ** ** This function writes out the sampled points linked list to an output ** file and then frees up memory. ** ** */ void writeout(){ dot * p; /* list ptr */ dot * freeMem=global.head; dot * temp; char fname[75]; FILE* outfile; fprintf(stderr,"Please type file name of output file.\n"); fscanf(stdin,"%s",fname); if ((outfile=fopen(fname,"w")) ==NULL){ fprintf(stderr," Error opening output file. Program terminating.\n"); exit(1); } /* write linked list to file */ for(p = global.head; p != NULL; p = (*p).next) { fprintf(outfile," %d %d %3hd %3hd %3hd \n", (*p).x, (*p).y, (*p).red, (*p).green, (*p).blue); } fclose(outfile); while (freeMem != NULL) { /* free up memory */ temp=(*freeMem).next; free(freeMem); freeMem = temp; } } /* ** keyboard: ** ** This is the keyboard callback function which handles the event ** that the user presses a key. ** ** key - the key pressed ** x - the x coordinate ** y - the y coordinate ** */ void keyboard(unsigned char key, int x, int y){ switch(key){ case 0x1B: /* esc key */ case 'Q': case 'q': case 'E': /* quitting case */ case 'e': writeout(); free(global.theImage); exit(0); break; } } /* ** plot_previous_points: ** ** This function plots the sampled points. ** */ void plot_previous_points(){ dot *p; /* list pointer */ glColor3f(0.0, 0.0, 0.0); glPointSize(3.0); glBegin(GL_POINTS); for (p=global.head; p != NULL; p = (*p).next) glVertex2i((*p).x-1,(*p).y-1); glEnd(); glFlush(); } /* ** Dump commands to screen. ** */ void dumpCommands() { fprintf(stderr," ****************************************************************\n"); fprintf(stderr," SUMMARY OF AVAILABLE COMMANDS\n"); fprintf(stderr," Read Previous File: r,R keys \n\n"); fprintf(stderr," Left Mouse Button: Add point to sample\n\n"); fprintf(stderr," Quit/Terminate: q,Q,e,E,esc keys \n"); fprintf(stderr," ****************************************************************\n\n"); } /* ** ** procInputData: ** ** Convert the user's window size param arguments. ** Do error checking on them. ** Allocate 2D array, and fill pixels with random RGB values. ** */ void procInputData(argc, argv) int argc; char **argv; { int x, y; int i; if (argc == 2 || argc > 4) { fprintf(stderr, "usage: newsample xsize ysize\n"); exit(1); } if (argc == 3) { sscanf(argv[1], "%d", &global.xSize); sscanf(argv[2], "%d", &global.ySize); } if (global.xSize > 1024 || global.ySize > 768) { fprintf(stderr, "Max window size: 1024 by 768\n"); exit(1); } //Allocate the memory for the image global.theImage = (colorPixel**)malloc(global.xSize*sizeof(colorPixel*)); for (i=0; i