1:  #include <stdlib.h>
2:  #include <stdio.h>
3:  #include <string.h>
4:  #include <math.h>
5:  #include <GL/glut.h>
6:  
7:  #define Round(v) ((int)(v+0.5))
8:  #define MAX 800
9:  #define MAX_FILE_LENGTH 256
10:    
11:  #define LOW_VALUE 0 
12:  #define HIGH_VALUE 255
13:  
14:  #define TRUE 1
15:  #define FALSE 0  
16:  
17:  /*#define BUFFERED*/
18:  
19:  /*cartesian coordinate type*/
20:  typedef struct {int x;
21:                  int y;}coord;  
22:  
23:  /*RGB color struct with floats*/ 
24:  /*typedef struct {float red;
25:                  float green;
26:                  float blue;
27:                 }RGB;
28:  */
29:  /*RGB color struct with ints*/  
30:  typedef struct {int red;
31:                  int green;
32:                  int blue;
33:                 }RGB_INT;
34:  
35:  /*number of chain codes stored, */  
36:  #define MAX_NUMBER_OF_CHAINS 10
37:  #define MAX_CHAINS MAX_NUMBER_OF_CHAINS
38:  
39:  /*These constant values are the chain code directions*/
40:  #define NONE      -1
41:  #define EAST      0
42:  #define NORTHEAST 1
43:  #define NORTH     2
44:  #define NORTHWEST 3
45:  #define WEST      4  
46:  #define SOUTHWEST 5
47:  #define SOUTH     6
48:  #define SOUTHEAST 7
49:  
50:  typedef struct chainCode* chain_t;
51:  typedef struct chainCode
52:  {
53:    chain_t prev;
54:    int code;    
55:    coord location; /*absolute pixel location for starting point*/
56:    chain_t next;
57:  }chainCode; /*This struct can be refered to by: struct chainCode or chainCode*/
58:  
59:  struct PGMstructure 
60:  {
61:    int maxVal;
62:    int width;
63:    int height;
64:    RGB_INT data[MAX][MAX];
65:  };
66:  
67:  typedef struct PGMstructure PGMImage;
68:  
69:  /*Evil globals, but not do-able otherwise.*/
70:  static PGMImage *img_cur;
71:  static PGMImage *img0; /*original*/
72:  static PGMImage *img1; /*current*/
73:  static PGMImage *img2; /*current*/
74:  static int HSIZE;
75:  static int VSIZE;
76:  static int MVAL;
77:  
78:  const RGB_INT white = {255, 255, 255};
79:  const RGB_INT yellow = {255, 255, 0};
80:  const RGB_INT purple = {255, 0, 255};
81:  const RGB_INT cyan = {0, 255, 255};
82:  const RGB_INT red = {255, 0, 0};
83:  const RGB_INT green = {0, 255, 0};
84:  const RGB_INT blue = {0, 0, 255};
85:  const RGB_INT black = {0, 0, 0};
86:  
87:  int cur_threash_val; /*for speed optimization of chain code recursion*/
88:  int back_ground;
89:  
90:  /*pointer to an array of pointers which point to the first nodes in each of
91:    the chain codes.*/ 
92:  chainCode **chain_codes;
93:  
94:  
95:  /*hold the points farthest away from each other for each object*/
96:  coord corner1[MAX_CHAINS], corner2[MAX_CHAINS];
97:  coord corner3[MAX_CHAINS], corner4[MAX_CHAINS];
98:  
99:  /**************Drawing funcitions************************************/
100:  /********************************************************************/
101:  
102:  void setCPixel(int ix, int iy, RGB_INT color)
103:  /*Same as setIPixel except that the last parameter is an RGB color*/
104:  {
105:    float x = (ix*2.0)/HSIZE - 1.0;
106:    float y = (iy*2.0)/VSIZE - 1.0;
107:  
108:    float red = (float)color.red/(float)MVAL;
109:    float green = (float)color.green/(float)MVAL;
110:    float blue = (float)color.blue/(float)MVAL;
111:  
112:    glColor3f(red, green, blue);
113:    
114:    glBegin(GL_POINTS); 
115:       glVertex2f (x, y);
116:    glEnd();
117:  }
118:  
119:  void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
120:  /*Similar as setIPixel except that this one draws a line between the first set
121:    of points given and the second set in the RGB color specified*/
122:  {
123:    float x1 = (ix1*2.0)/HSIZE - 1.0;
124:    float y1 = (iy1*2.0)/VSIZE - 1.0;
125:    float x2 = (ix2*2.0)/HSIZE - 1.0;
126:    float y2 = (iy2*2.0)/VSIZE - 1.0;
127:   
128:    float red = (float)color.red/(float)MVAL;
129:    float green = (float)color.green/(float)MVAL;
130:    float blue = (float)color.blue/(float)MVAL;
131:  
132:    glColor3f(red, green, blue);
133:  
134:    glBegin(GL_LINES);
135:      glVertex2f (x1, y1);
136:      glVertex2f (x2, y2);
137:    glEnd();
138:  }
139:  
140:  void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
141:  /*Similar as setIPixel except that this one draws a line between the first set
142:    of points given and the second set in the RGB color specified*/
143:  {
144:    float x1 = (ix1*2.0)/HSIZE - 1.0;
145:    float y1 = (iy1*2.0)/VSIZE - 1.0;
146:    float x2 = (ix2*2.0)/HSIZE - 1.0;
147:    float y2 = (iy2*2.0)/VSIZE - 1.0;
148:   
149:    float red = (float)color.red/(float)MVAL;
150:    float green = (float)color.green/(float)MVAL;
151:    float blue = (float)color.blue/(float)MVAL;
152:  
153:    glColor3f(red, green, blue);
154:  
155:    glBegin(GL_POLYGON);
156:      glVertex2f (x1, y1);
157:      glVertex2f (x1, y2);
158:      glVertex2f (x2, y2);
159:      glVertex2f (x2, y1);
160:    glEnd();
161:  }
162:  
163:  void pxlcpy(PGMImage *dest, int dest_row, int dest_col,
164:  	    PGMImage *src, int src_row, int src_col)
165:  {
166:    /*make sure values are within bounds*/
167:    if(dest_col > 0 && dest_col < (*dest).width
168:       && dest_row > 0 && dest_row < (*dest).height
169:       && src_col > 0 && src_col < (*src).width
170:       && src_row > 0 && src_row < (*src).height)
171:    {
172:      (*dest).data[dest_row][dest_col].red =
173:        (*src).data[src_row][src_col].red;
174:  
175:      (*dest).data[dest_row][dest_col].green =
176:        (*src).data[src_row][src_col].green;
177:  
178:      (*dest).data[dest_row][dest_col].blue =
179:        (*src).data[src_row][src_col].blue;
180:    }
181:  } 
182:  
183:  
184:  /**********************Support functions*******************************/
185:  /***********************************************************************/
186:  
187:  int rgb_avg(RGB_INT cur_pxl)
188:  {
189:     /*convert each RGB to the average of the original*/
190:     return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3);
191:  }
192:  
193:  /*Returns average (with RGB avg) pixel value for the image passed in.*/
194:  int img_pxl_avg(PGMImage* img)
195:  {
196:     int i, j; /*loop counting*/
197:     int sum = 0;
198:  
199:     for(i = 0; i < (*img).height; i++)/*collumn*/
200:        for(j = 0; j < (*img).width; j++)/*row*/
201:           sum += rgb_avg((*img).data[i][j]);
202:  
203:     return (sum / ((*img).height * (*img).height));
204:  }
205:  
206:  /*1st: pixel one of type RGB_INT
207:  2nd: pixel one of type RGB_INT
208:  3rd: differnce allowed to be considered "equal" or close enough*/
209:  int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range)
210:  {
211:    return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) < range);
212:  }
213:  
214:  /* ================================================================= 
215:   * drawString - outputs a string of characters to the graphics port
216:   *
217:   *   x, y:      defines the starting location to draw the text
218:   *               note: this point is the lower left anchor of
219:   *                     the first character - a character's decending
220:   *                     portion would be drawn below this point.
221:   *   theFont:   points to the glut font to be used
222:   *   theString: holds the string to be output -- up to 255 ch
223:   * ----------------------------------------------------------------- */
224:  void drawString(int ix, int iy, void *theFont, char theString[256])
225:  {
226:     float x = (ix*2.0)/HSIZE - 1.0;
227:     float y = (iy*2.0)/VSIZE - 1.0;
228:     int i;
229:     glRasterPos2f(x, y);
230:     for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */
231:       glutBitmapCharacter(theFont, theString[i]);
232:  }
233:  
234:  /*return >0 if number of pixels is greater than img. pxl. avg., return <0 if
235:    number of pixesl is less than img. pxl. avg. and return zero of equal*/
236:  int background(int treash_value, PGMImage* img)
237:  {
238:     int i, j; /*loop counting*/
239:     int pxl_less = 0, pxl_more = 0;
240:  
241:     for(i = 0; i < (*img).height; i++)/*collumn*/
242:        for(j = 0; j < (*img).width; j++)/*row*/
243:        {
244:  	 if(rgb_avg((*img).data[i][j]) < treash_value)
245:  	   pxl_less++;
246:  
247:           if(rgb_avg((*img).data[i][j]) > treash_value)
248:  	   pxl_more++;
249:        }
250:  
251:     if(pxl_less > pxl_more)
252:        return -1;
253:     else if(pxl_less < pxl_more)
254:        return 1;
255:     else
256:        return 0;
257:  }
258:  
259:  /******CHAIN CODE************************************************
260:  ****************************************************************/
261:  
262:  int createNode(chainCode** first, chainCode** last, int new_x, int new_y,
263:  	       int new_dir)
264:  {
265:     chainCode* temp;
266:  
267:     if(!(temp = (chain_t)malloc(sizeof(struct chainCode))))
268:     {
269:       printf("error creating node\n");
270:        return FALSE;
271:     }
272:  
273:     temp->next = NULL;
274:     temp->code = new_dir;
275:     temp->location.x = new_x;
276:     temp->location.y = new_y;
277:     temp->prev = *last;
278:     if(*last)
279:       (*last)->next = temp;  /*now this is a good thing to set.*/
280:     *last = temp;  /*advance one*/
281:     
282:     if(*first == NULL)
283:       *first = *last;/*set this for the first node in the list once*/
284:  
285:     return TRUE;
286:  }
287:  
288:  /*returns TRUE if the chain code loops around itself, otherwise false*/
289:  int checkCode(chainCode* first, int x_current, int y_current,
290:  	      int x_check, int y_check, int dir)
291:  {
292:     struct chainCode* currentNode = first;
293:  
294:     while(currentNode && currentNode->next)
295:     {
296:        /*check two consedutive points*/
297:        if((currentNode->location.x == x_current) &&
298:           (currentNode->location.y == y_current) &&
299:           (currentNode->code == dir) &&
300:           (currentNode->next->location.x == x_check) &&
301:           (currentNode->next->location.y == y_check) &&
302:  	 (currentNode->next->next)) /*don't count the new node already*/
303:  	{
304:           return TRUE; /*The chain code end looped around*/
305:  	}
306:        else
307:           currentNode = currentNode->next;
308:     }
309:     return FALSE;
310:  }
311:  
312:  /*
313:  Preconditions:
314:  1st parameter: integer value containing the current x coordinate.
315:  2nd parameter: integer value containing the current y coordinate.
316:  3rd parameter: pointer to the pgm image being used.
317:  Postconditions:  return true if pixel is deemed boarder of object, false
318:     otherwise.*/
319:  int checkThings(int x_check, int y_check, PGMImage *img)
320:  {
321:  
322:     /*check for being in bounds*/
323:     if((x_check < 0) || (y_check < 0) || (x_check >= (*img).width) ||
324:        (y_check >= (*img).height))
325:        return FALSE;
326:  
327:     /*tests if the next pixel is greater than the threashing value.  This 
328:        value (cur_threash_val) should be set to the return value of 
329:        img_pxl_avg().  Also, checks if the pixel is considered in the background
330:        or forground agains the value in back_ground.  If so, return true to
331:        indicate create new node.*/
332:     if((rgb_avg((*img).data[y_check][x_check]) > cur_threash_val)
333:        && (back_ground < 0))
334:        return TRUE;   
335:  
336:     /*same thing as above, just for things less than, rathur than greater than*/
337:     if((rgb_avg((*img).data[y_check][x_check]) < cur_threash_val)
338:       && (back_ground > 0))
339:        return TRUE;
340:  
341:     return FALSE;
342:  }  
343:  
344:  coord neighborhood_point(int x_coord, int y_coord, int dir)
345:  {
346:     coord temp = {x_coord, y_coord};
347:  
348:     if(dir == EAST)
349:        temp.x++;
350:     else if(dir == NORTHEAST)
351:     {
352:        temp.x++;
353:        temp.y++;
354:     }
355:     else if(dir == NORTH)
356:        temp.y++;
357:     else if(dir == NORTHWEST)
358:     {
359:        temp.x--;
360:        temp.y++;
361:     }
362:     else if(dir == WEST)
363:        temp.x--;
364:     else if(dir == SOUTHWEST)
365:     {
366:        temp.x--;
367:        temp.y--;
368:     }
369:     else if(dir == SOUTH)
370:        temp.y--;
371:     else if(dir == SOUTHEAST)
372:     {
373:        temp.x++;
374:        temp.y--;
375:     }
376:  
377:     return temp;
378:  }
379:  
380:  /*determines the chain code for a starting pixel*/
381:  /*this chain code uses 8 connectivity*/
382:  /*Note: There are many different coordinate systems at work in this function.*/
383:  /*The (*img).data[][] are column major and have are therefore [y][x] or [j][i]*//*   This is also asuming (0,0) is bottom left, where the other code assumes
384:  /*   top left is (0, 0).  If it looks strange, look harder!!!*/
385:  /*Preconditions:
386:  1st parameter: pointer to the pgm image being used.
387:  2nd parameter: integer value containing the current x coordinate.
388:  3rd parameter: integer value containing the current y coordinate.
389:  4th parameter: integer value containing the current direction code.
390:  5th parameter: pointer to the last node of the chain code.
391:  6th parameter: pointer to the first node of the chain code.*/
392:  /*This function assumes the (0, 0) point is in the lower left*/
393:           
394:  int chaincode(PGMImage *img, int x, int y, int dir,
395:     struct chainCode** last, struct chainCode** first)   
396:  {
397:     int i; /*loop counting*/
398:     int next /*next direction to check*/, finished /*finished flag*/;
399:     coord next_point_to_check; /*next_point_to_check What else?*/
400:  
401:     next = (dir + 5) % 8; /*better initail choice?*/
402:  
403:  /*printf("next: %d  x: %d  y: %d\n", next, x, y);*/
404:     for(i = 0; i < 8; i++)
405:     {
406:        /*determine the next point to check*/
407:        next_point_to_check = neighborhood_point(x, y, next);
408:  
409:        if(checkThings(next_point_to_check.x, next_point_to_check.y, img))
410:        {
411:  /*setCPixel(next_point_to_check.x, next_point_to_check.y, blue);*/
412:  
413:  	 /*create the new node to go last in the chain*/
414:  	 createNode(first, last, next_point_to_check.x,
415:  		    next_point_to_check.y, next);
416:  
417:  	 /*if the next chaincode function in the recursion or the current state
418:           is the final state of the the chain code; recursively returns DONE
419:           back through all the levels to stop the chain code.*/
420:  	 if(checkCode(*first, x, y, next_point_to_check.x,
421:  		    next_point_to_check.y, dir))
422:  	 {
423:  	    return NONE;
424:  	 }
425:  
426:  	 if(NONE == chaincode(img, next_point_to_check.x,
427:  			      next_point_to_check.y, next, last, first))
428:  	    return NONE;
429:        }
430:  
431:        /*set next for next iteration*/
432:        next = (next + 1) % 8;
433:     }
434:     return FALSE;         
435:  }
436:  
437:  /*returns true if the point is already in one of the chains, false otherwise*/
438:  int alreadyFound(int initThreashFlag, int i, int j, chainCode** found)
439:  {
440:     int k; /*loop counting*/
441:     chainCode* temp; /*temporary node pointer*/
442:  
443:     /*while there are codes to check...*/
444:     for(k = 0; (temp = (found[k])) && k < MAX_NUMBER_OF_CHAINS; k++)
445:     {
446:        while(temp) /*...check them.*/
447:        {
448:  	 /*if point has already been found*/
449:  	 if((temp->location.x == i) && (temp->location.y == j))
450:  	 {
451:  	    return TRUE;
452:  	    break;
453:  	 } 
454:  	 temp = temp->next;
455:        }
456:     }
457:     
458:     return FALSE;
459:  }
460:  
461:  /*saves a chain code to file.  Was usefull during debuging now is just
462:    a cool thing to leave in*/
463:  /*1st: pointer to beginning of a chaincode
464:  2nd: the index of the chain code for destiqushing the 'chain' files*/
465:  void saveChainCode(chainCode* saveChain, int count)
466:  {
467:     struct chainCode* temp = saveChain;
468:     char filename[12];
469:     FILE* outfile;
470:     sprintf(filename, "chain%d", count);
471:     outfile = fopen(filename, "w");   /*output file for chaincode*/
472:     printf("Writing chain code to file %s.\n", filename);
473:  
474:     while(temp)
475:     {
476:     
477:        fprintf(outfile, "%d  %d  %d\n",temp->location.x,temp->location.y,
478:           temp->code);
479:        temp = temp->next;
480:     }
481:     fclose(outfile);
482:  }
483:  
484:  chainCode** showChain(PGMImage *original)
485:  {
486:     int i, j;  /*loop counting*/
487:     int count = 0; /*array index holder*/
488:     int initThreashFlag = img_pxl_avg(original);
489:     /*beginning points to an array of pointers.  Each pointer in the array is
490:       a pointer to the first node of MAX_NUMBER_OF_CHAINS number of chain
491:       codes*/
492:     struct chainCode** beginning, *chain = NULL;
493:      
494:     /*allocate an array of pointers to chainCodes, then initalize their
495:       values to NULL*/
496:     beginning = (chainCode**)
497:       malloc(MAX_NUMBER_OF_CHAINS * sizeof(chainCode*));
498:     memset(beginning, 0, MAX_NUMBER_OF_CHAINS * sizeof(chainCode*));
499:                
500:     cur_threash_val = initThreashFlag; /*set global variables*/
501:     back_ground = background(initThreashFlag, original);
502:  
503:     /*search image until a pixel is found with threasholded value of the
504:     object.  i & j will then contain the starting coordinate.*/
505:     for(i = 0; i < (*original).width; i++) /*x direction*/
506:     {
507:        for(j = (*original).height - 1; j >= 0; j--) /*y direction*/
508:        {
509:           /*skip to the next iteration if pixel isn't "good" enough*/
510:           if(!checkThings(i, j, original))
511:              continue;
512:  
513:           /*skip to the next iteration, which will be at the top of the next
514:             collumn.  This is true when the pixel has already been found in
515:  	   one of the chain codes.*/
516:           else if(alreadyFound(initThreashFlag, i, j, beginning))
517:  	    break;
518:  
519:           else
520:           {
521:  /*printf("chaincode: %d\n", count);*/
522:             /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/
523:              chain = NULL; /*reset this to seperate the chaincodes*/
524:  
525:              /*find the chaincode for the current starting pixel*/
526:              chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]);
527:  	    if(beginning[count] != NULL) /*avoid writing zero length chains*/
528:  	    {
529:  	       saveChainCode(beginning[count], count);
530:  	       count++; /*advance the beginning counter*/
531:  	    }
532:  
533:  	    /*force end of loops, leaving code when finished looping
534:  	      to still execute*/
535:  	    if(count >= MAX_NUMBER_OF_CHAINS)
536:  	       i = (*original).width;
537:  
538:              break; /*check the next collumn*/
539:           }
540:        }   
541:     }
542:     printf("Done finding chain code(s).  %d were found.\n", count);
543:     return beginning;
544:  }
545:  
546:  /*****BOUNDRY BOX**********************************************************
547:   **********************************************************************/
548:     
549:  /*takes two coordinates as x and y pairs and returns the distence betweem them
550:     as a decimal*/
551:  float findDist(int x1, int y1, int x2, int y2)
552:  {
553:     return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
554:  }
555:           
556:  /*1st param: The array of coords that the first point of the major axis is
557:     returned in.
558:  2nd: The array of coords that the second point of the major axis is
559:     returned in.
560:  3rd: The array of chain codes that are searched through to find the major
561:     axes.*/
562:  /* Note: the ending condition is when a NULL chainCodes value is reached.
563:     Thusly, it works like a string requiring it to have the last legal value
564:     followed by a null value.*/
565:  void findFirstTwoCorners(coord corner1[], coord corner2[],
566:  			 chainCode** chainCodes)
567:  {
568:     int i; /*loop counting*/
569:     chainCode *temp, *search;
570:     double max_dist, test_dist;
571:  
572:     printf("\nFinding first 2 corners.\n");
573:  
574:     /*as long as there are codes to check, keep checking.  Note: the ending
575:     condition is when a NULL chainCodes value is reached.  Thusly, it works
576:     like a string requiring it to have the last legal value followed by a
577:     null value.*/
578:     for(i = 0; (temp = chainCodes[i]) && (i < MAX_CHAINS); i++)
579:     {      
580:        max_dist = 0.0;  /*reset this for each iteration*/
581:  
582:  /*printf("checking list: %d\n", i);*/
583:  
584:        while(temp) /*while there are still nodes to check in the chain*/
585:        {
586:           search = temp; /*set the faster moving search pointer to temp,
587:                            this increases the effiecency a lot compared to
588:  			  setting it equal to the first node..*/
589:           while(search)
590:           {
591:  /*setCPixel(temp->location.x, temp->location.y, green);*/
592:  
593:              /*determine if found a new maximum distance between two locations*/
594:              if((test_dist = findDist(search->location.x, search->location.y,
595:                 temp->location.x, temp->location.y)) > max_dist)
596:              {
597:                 max_dist = test_dist;
598:                 corner1[i].x = temp->location.x;
599:                 corner1[i].y = temp->location.y;
600:                 corner2[i].x = search->location.x;
601:                 corner2[i].y = search->location.y;
602:              }
603:              search = search->next;
604:           }
605:           temp = temp->next;
606:        }
607:  /*printf("point1: %d  %d\n", max1[i].x, max1[i].y);
608:  printf("point2: %d  %d\n", max2[i].x, max2[i].y);*/
609:     }
610:  }
611:  
612:  /*1st param: Array of coords for the first corner of each chain code.
613:  2nd param: Array of coords for the second corner of each chain code.
614:  The first two parameters should equal the first two parameters "returned"
615:  from the findFirstTwoCorners() function.
616:  3rd: Array of coords "returned" with the third corners.
617:  4th:  Array of coords "returned" with the fourth corners.
618:  5th: Pointer pointing to the array of chaincode pointers, obtained from
619:    showChain().*/
620:  void findSecondTwoCorners(coord corner1[], coord corner2[], coord corner3[],
621:  		 coord corner4[], chainCode** chain_code_array)
622:  {
623:     int i; /*loop counting*/
624:     chainCode* temp;
625:     float temp_dist1, temp_dist2; /*distance between point and each corner*/
626:     coord canidate_coord1, temp_coord;
627:     float canidate_dist1, max_dist;
628:     int corner_count;
629:  
630:     printf("\nFinding last 2 corners.\n");
631:  
632:     /*for each chain code find the corners*/
633:     for(i = 0; chain_code_array[i] && i < MAX_CHAINS; i++)
634:     {
635:        temp = chain_code_array[i];
636:        
637:        /*reset these for the next chain code*/
638:        max_dist = 0.0;
639:        corner_count = 1;
640:  
641:        while(temp) /*while there are nodes in the chain code to check*/
642:        {
643:  /*setCPixel(temp->location.x, temp->location.y, color1);*/
644:  
645:  	/*determine the first canidate coord for corner 3/4*/
646:  	if(((temp->location.x == corner1[i].x)
647:  	    && (temp->location.y == corner1[i].y))
648:  	   || ((temp->location.x == corner2[i].x)
649:  	       && (temp->location.y == corner2[i].y)))
650:  	{
651:  	  /*if this corner found is the first of the two allready known
652:  	    corners, then set the first canidate coord data and reset data
653:  	    to find the next canidate corner point*/
654:  	   if(corner_count == 1)
655:  	   {
656:  	      canidate_coord1.x = temp_coord.x;
657:  	      canidate_coord1.y = temp_coord.y;
658:  	      canidate_dist1 = max_dist;
659:  
660:  	      corner_count = 2; /*set for next corner*/
661:  	      max_dist = 0.0;
662:  	   }
663:  	   else if(corner_count == 2)
664:  	   {
665:  	      /*the second canidate is always a corner*/
666:  	      corner4[i].x = temp_coord.x;
667:  	      corner4[i].y = temp_coord.y;
668:  	      
669:  	      max_dist = 0.0; /*set for next corner canidate*/
670:  	   }
671:  	}
672:  
673:  	/*calculate the distance between the current point being checked and
674:  	  each corner point*/
675:  	temp_dist1 = findDist(corner1[i].x, corner1[i].y, temp->location.x,
676:  			      temp->location.y);
677:  	temp_dist2 = findDist(corner2[i].x, corner2[i].y, temp->location.x,
678:  			      temp->location.y);
679:  
680:  	/*if the current point is the furthest away sofar, store this point
681:  	  untill it is overridden or becomes a canidate point*/
682:  	if((temp_dist1 + temp_dist2) > max_dist)
683:  	{
684:  	   temp_coord.x = temp->location.x;
685:  	   temp_coord.y = temp->location.y;
686:  	  
687:  	   max_dist = (temp_dist1 + temp_dist2);
688:  	}
689:  
690:  	temp = temp->next; /*advance*/
691:        }
692:  
693:        /*from the three canidate coords find the two real corners.*/
694:        /*the second canidate will always be a corner, must test 1 vs 3, where
695:  	three is in the variables temp_coord and max_dist.*/
696:        if(canidate_dist1 > max_dist) /*first canidate*/
697:        {
698:           corner3[i].x = canidate_coord1.x;
699:  	 corner3[i].y = canidate_coord1.y;
700:        }
701:        else /*third canidate*/
702:        {
703:           corner3[i].x = temp_coord.x;
704:  	 corner3[i].y = temp_coord.y;
705:        }
706:  /*printf("corner3: (%d, %d)  corner4: (%d, %d)\n", corner3[i].x,
707:    corner3[i].y, corner4[i].x, corner4[i].y);*/
708:     }
709:  }
710:  
711:  /*takes a pointer to an image, and a pointer pointing to an array of
712:    chain codes pointers, here each chainCode pointer needs to be accessed
713:    by calculating the memory address.*/
714:  void showBound(PGMImage *original, chainCode** chainCodes)
715:  {     
716:     int i;
717:  
718:     /*find the first two corners.  they will be across a diagnal.*/
719:     findFirstTwoCorners(corner1, corner2, chainCodes);
720:     /*find the second two corners.  they will be across a diagnal too.*/
721:     findSecondTwoCorners(corner1, corner2, corner3, corner4, chainCodes);
722:     /*     
723:     for(i = 0; chainCodes[i] && i < MAX_CHAINS; i++)
724:     {
725:        setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
726:        setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
727:        setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
728:        setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
729:        setCPixel(corner1[i].x, corner1[i].y, purple);
730:        setCPixel(corner2[i].x, corner2[i].y, purple);
731:        setCPixel(corner3[i].x, corner3[i].y, purple);
732:        setCPixel(corner4[i].x, corner4[i].y, purple);
733:        }*/
734:  }
735:  
736:  /**********************File I/O functions*******************************/
737:  /***********************************************************************/
738:  
739:  /*Gets an ascii color pgm image file (type P3).*/
740:  void getPGMfile (char filename[], PGMImage *img)
741:  {
742:    FILE *in_file;
743:    char ch;
744:    int row, col;
745:  
746:    in_file = fopen(filename, "r");
747:    if (in_file == NULL)
748:    {
749:      fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
750:      exit(8);
751:    }
752:  
753:    printf("\nReading image file: %s", filename);
754:    
755:    do                                        /* skip header identifier */
756:      ch = getc(in_file);
757:    while (ch != '\n');
758:  
759:    do                                        /* skip comments lines    */
760:    {
761:      while (ch != '\n') ch = getc(in_file);  /*  flush to end of line  */
762:      ch = getc(in_file);
763:    } while (ch == '#');
764:   
765:    fseek(in_file, -1, SEEK_CUR);             /* backup one character   */
766:  
767:    fscanf(in_file,"%d", &((*img).width));
768:    fscanf(in_file,"%d", &((*img).height));
769:    fscanf(in_file,"%d", &((*img).maxVal));
770:  
771:    printf("\n width  = %d",(*img).width);
772:    printf("\n height = %d",(*img).height);
773:    printf("\n maxVal = %d",(*img).maxVal);
774:    printf("\n");
775:   
776:    if (((*img).width > MAX) || ((*img).height > MAX))
777:    {
778:      printf("\n\n***ERROR - image too big for current image structure***\n\n");
779:      exit(0);
780:    }
781:  
782:    for (row=(*img).height-1; row>=0; row--)
783:      for (col=0; col<(*img).width; col++)
784:      {
785:        fscanf(in_file,"%d", &((*img).data[row][col].red) );
786:        fscanf(in_file,"%d", &((*img).data[row][col].green));
787:        fscanf(in_file,"%d", &((*img).data[row][col].blue));
788:      }
789:    fclose(in_file);
790:    printf("\nDone reading file.\n");
791:  }
792:  
793:  
794:  void save(PGMImage *img)
795:  {
796:     int i, j, nr, nc, k;
797:     int red, green, blue;
798:     FILE *iop;
799:  
800:     nr = img->height;
801:     nc = img->width;
802:      
803:     iop = fopen("image1.pgm", "w");
804:     fprintf(iop, "P3\n");
805:     fprintf(iop, "%d %d\n", nc, nr);
806:     fprintf(iop, "255\n");
807:      
808:     k = 1;
809:     for(i = nr - 1; i >= 0; i--)
810:     {
811:        for(j = 0; j < nc; j++)
812:        {
813:           red = img->data[i][j].red;
814:           green = img->data[i][j].green;
815:           blue = img->data[i][j].blue;
816:           if(red < 0)
817:           {
818:              printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
819:              printf("           Setting red to zero\n");
820:              red = 0;
821:           }
822:           if(green < 0)   
823:           {
824:              printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
825:              printf("           Setting green to zero\n");
826:              green = 0;
827:           }
828:           if(blue < 0)   
829:           {
830:              printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
831:              printf("           Setting green to zero\n");
832:              blue = 0;
833:           }
834:           if(red > 255) 
835:           {   
836:              printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
837:              printf("           Setting red to 255\n");
838:              red = 255;
839:           }
840:           if(green > 255)
841:           {
842:              printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
843:              printf("           Setting green to 255\n");
844:              green = 255;
845:           }
846:           if(blue > 255)
847:           {
848:              printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
849:              printf("           Setting blue to 255\n");
850:              blue = 255;
851:           }
852:  
853:           if(k % 10)
854:           {
855:              fprintf(iop, "%d ", red);
856:              fprintf(iop, "%d ", green);
857:              fprintf(iop, "%d ", blue);
858:           }
859:           else /*for newline*/
860:           {
861:              fprintf(iop, "%d\n", red);
862:              fprintf(iop, "%d\n", green);
863:              fprintf(iop, "%d\n", blue);
864:           }
865:           k++;
866:        }
867:     }
868:     fprintf(iop, "\n");
869:     fclose(iop);
870:  }
871:  
872:  
873:  /****Calculation & drawing functions of the image translations**********
874:  ***********************************************************************/
875:  
876:  void error(char* message)
877:  {
878:     printf("%s\n");
879:     exit(1);
880:  }
881:              
882:  void showColor (PGMImage *img)
883:  {
884:     int i, j; /*loop counting: i = y, j = x*/
885:  
886:     GLubyte checkImage[(*img).height][(*img).width][3];
887:  
888:     for(i = 0; i < (*img).height; i++)
889:     {
890:        for(j = 0; j < (*img).width; j++)
891:        {
892:           checkImage[i][j][0] = (GLubyte) (*img).data[i][j].red;
893:           checkImage[i][j][1] = (GLubyte) (*img).data[i][j].green;
894:           checkImage[i][j][2] = (GLubyte) (*img).data[i][j].blue;
895:        }
896:     }
897:     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
898:  
899:     glDrawPixels((*img).width, (*img).height, GL_RGB,
900:                  GL_UNSIGNED_BYTE, checkImage);
901:  
902:     /*first check for non-null pointer, next check for dereferenced pointers
903:       in the array of head pointers and lastly make sure things stay in
904:       bound of the max incase all MAX_CHAINS number of chains are used.*/
905:     for(i = 0; chain_codes && chain_codes[i] && i < MAX_CHAINS; i++)
906:     {
907:        setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
908:        setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
909:        setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
910:        setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
911:        setCPixel(corner1[i].x, corner1[i].y, purple);
912:        setCPixel(corner2[i].x, corner2[i].y, purple);
913:        setCPixel(corner3[i].x, corner3[i].y, purple);
914:        setCPixel(corner4[i].x, corner4[i].y, purple);
915:     }
916:  
917:     glFlush();
918:  }
919:  
920:  void camera_correction(PGMImage* new_img, PGMImage* org_img)
921:  {
922:     int row, col, img_row, img_col; /*loop counting*/
923:  
924:     /*camera parameters*/
925:     float height = 30; /*height of camera in cm*/
926:     float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
927:     float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
928:     
929:     /*temporary varaibles*/
930:     float angular_height_corr;
931:     float angular_side_corr;
932:     int x_coord, y_coord;
933:  
934:     memset(new_img, 0, sizeof(PGMImage));
935:     (*new_img).height = (*org_img).height;
936:     (*new_img).width = (*org_img).width;
937:     (*new_img).maxVal = (*org_img).maxVal;
938:  
939:     for (row=(*org_img).height-1; row>=0; row--)
940:        for (col=0; col<(*org_img).width; col++)
941:        {
942:  	/*img_row -= (*org_img).height / 2;
943:  	  img_col = col - (*org_img).width / 2;*/
944:  
945:  	 angular_height_corr = 
946:     (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
947:  	 angular_side_corr =
948:     (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
949:  
950:  	 angular_height_corr /= 2;
951:  	 /*angular_side_corr /= 2;*/
952:           /*height *= 2;*/
953:  	 height = 150;
954:  
955:  	 x_coord = (int)
956:  	   (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
957:  	 y_coord = (int)
958:  	   (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
959:  
960:  	 /*x_coord += (*org_img).width / 2;*/
961:  	 y_coord += (*org_img).height / 2;
962:  
963:  	 /*printf("org: (%d, %d)  new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
964:  
965:  	 pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
966:        }
967:  }
968:  
969:  void new_corr(PGMImage* new_img, PGMImage* org_img)
970:  {
971:     /*i and j are the left half, k and l are the right half*/
972:     float i, k; /*loop counting*/
973:     int j, l, row; /*loop counting*/
974:     int old_i, old_k;
975:  
976:     float ins_s = 2; /*insert constant starting value*/
977:     float ins_k = ins_s; /*insert constant*/
978:  
979:     /*The halfway marks in the width.*/
980:     int mid_width_left = ((*new_img).width / 2) - 1;
981:     int mid_width_right = ((*new_img).width / 2);
982:     
983:     /*just to be thourough clear the memory and reset maxes*/
984:     memset(new_img, 0, sizeof(PGMImage));
985:     (*new_img).height = (*org_img).height;
986:     (*new_img).width = (*org_img).width;
987:     (*new_img).maxVal = (*org_img).maxVal;
988:  
989:     /*Loop through each row from top to bottom...*/
990:     for(row = ((*new_img).height - 1); row >= 0; row--)
991:     {
992:        /*...reset moire interference removal counter...*/
993:        old_i = ((*new_img).width / 2) - 1;
994:        old_k = ((*new_img).width / 2);
995:  
996:        /*...so each half is ajusted to remove perspective effect...*/
997:        for(i = j = mid_width_left, k = l = mid_width_right
998:  	    ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width
999:  	    ; i -= ins_k, j--, k += ins_k, l++)
1000:        {
1001:  	 for(;old_i >= (int)i; old_i--)  /*...in the left half...*/ 
1002:  	    pxlcpy(new_img, row, old_i, org_img, row, j);
1003:  	 for(;old_k <= (int)k; old_k++)  /*...in the right half.*/
1004:  	    pxlcpy(new_img, row, old_k, org_img, row, l);
1005:        }
1006:        /*Move the new image x_coord pixel counter to next new image pixel*/
1007:        ins_k -= ((ins_s - 1.0) / (*new_img).height);
1008:     }
1009:  }
1010:  
1011:  void color_to_gray(PGMImage* new_img, PGMImage* org_img)
1012:  {
1013:     int row, col; /*loop counting*/
1014:     RGB_INT cur_pxl; /*current pixel*/
1015:  
1016:     (*new_img).height = (*org_img).height;
1017:     (*new_img).width = (*org_img).width;
1018:     (*new_img).maxVal = (*org_img).maxVal;
1019:  
1020:     /*Starting with the top row...*/
1021:     for(row = (*new_img).height - 1; row >= 0; row--)
1022:        for(col = 0; col < (*new_img).width - 1; col++)
1023:        {
1024:  	 cur_pxl = (*org_img).data[row][col]; /*more readable*/
1025:  	
1026:  	 /*convert each RGB to the average of the original*/
1027:  	 (*new_img).data[row][col].red =  rgb_avg(cur_pxl);
1028:  	 (*new_img).data[row][col].green =  rgb_avg(cur_pxl);
1029:  	 (*new_img).data[row][col].blue =  rgb_avg(cur_pxl);
1030:        }
1031:  }
1032:  
1033:  void moravec(PGMImage* new_img, PGMImage* org_img)
1034:  {
1035:     int row, col; /*loop counting*/
1036:     int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1037:     int running_sum;
1038:     float K = .5; /*.125 according to org. formula, but .5 is brighter*/
1039:     int max_val = 0, row_max, col_max; /* max porportion value in image*/
1040:  
1041:     memset(new_img, 0, sizeof(PGMImage));
1042:     (*new_img).height = (*org_img).height;
1043:     (*new_img).width = (*org_img).width;
1044:     (*new_img).maxVal = (*org_img).maxVal;
1045:  
1046:     /*starting at the top row*/
1047:     for(row = (*new_img).height - 1 - 1; row > 0; row--)
1048:        for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/
1049:        {
1050:  	 i = row;
1051:  	 j = col;
1052:  	 running_sum = 0;
1053:  
1054:  	 /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1055:  	 for(k = i - 1; k <= i + 1; k++) /*row*/
1056:  	   for(l = j - 1; l <= j + 1; l++) /*column*/
1057:  	     running_sum += abs(rgb_avg((*org_img).data[k][l]) -
1058:  				rgb_avg((*org_img).data[i][j]));
1059:  
1060:  	 /*assign the new pixel value*/
1061:  	 (*new_img).data[row][col].red = (int)(K * running_sum);
1062:  	 (*new_img).data[row][col].green = (int)(K * running_sum);
1063:  	 (*new_img).data[row][col].blue = (int)(K * running_sum);
1064:        } 
1065:  }
1066:  
1067:  void detect_corners(PGMImage* org_img)
1068:  {
1069:     glPointSize(4); /*make points more visible, if desired*/
1070:     glLineWidth(4);
1071:  
1072:     chain_codes = showChain(org_img);
1073:     showBound(org_img, chain_codes);
1074:  }
1075:  
1076:  /* =================================================================
1077:   * Callback functions.
1078:   *
1079:   * color = displayed graphics in window
1080:   * menu = menu event handling
1081:   * keyboard = deyboard event handling
1082:   * ----------------------------------------------------------------- */
1083:  void color(void)
1084:  {
1085:    /*glClear (GL_COLOR_BUFFER_BIT);*/
1086:  
1087:     /*  printf("\nDrawing Original image...\n");*/
1088:    showColor(img_cur);
1089:     
1090:    /*glFlush();*/
1091:  #ifdef BUFFERED
1092:    glutSwapBuffers();
1093:  #endif
1094:  }
1095:  
1096:  #define RESTART 0
1097:  #define CAMERA_CORRECTION 1
1098:  #define X2_C_CORR 2
1099:  #define NEW_CORR 3
1100:  #define COLOR_TO_GRAY 4
1101:  #define MORAVEC 5
1102:  #define CORNERS 6
1103:  
1104:  void menu(int selection)
1105:  {
1106:     if(selection == RESTART)   
1107:     {
1108:        memcpy(img1, img0, sizeof(PGMImage));
1109:        img_cur = img0;
1110:     }
1111:     if(selection == CAMERA_CORRECTION)
1112:     {
1113:        printf("Starting camera correction\n");
1114:        camera_correction(img1, img0);
1115:        img_cur = img1;
1116:      }
1117:      if(selection == X2_C_CORR)
1118:      {
1119:         printf("Starting camera correction\n");
1120:         camera_correction(img1, img0);
1121:         camera_correction(img2, img1);
1122:         img_cur = img2;
1123:      }
1124:      if(selection == NEW_CORR)
1125:      {
1126:         new_corr(img1, img0);
1127:         img_cur = img1;
1128:      }
1129:      if(selection == COLOR_TO_GRAY)
1130:      {
1131:         color_to_gray(img1, img0);
1132:         img_cur = img1;
1133:      }
1134:      if(selection == MORAVEC)
1135:      {
1136:         moravec(img1, img0);
1137:         img_cur = img1;
1138:      }
1139:      if(selection == CORNERS)
1140:      {
1141:         new_corr(img1, img0);
1142:         showColor(img1);
1143:         detect_corners(img1);
1144:         img_cur = img1;
1145:      }
1146:  
1147:      glutPostRedisplay();
1148:  }
1149:  
1150:  void keyboard(unsigned char key, int x, int y)
1151:  { 
1152:     switch (key)
1153:     {
1154:        case 27: 
1155:           exit(0);
1156:           break;
1157:     }
1158:  }
1159:  
1160:  void mouse(int button, int state, int x, int y)
1161:  {
1162:    char temp[50];
1163:    
1164:    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1165:    {
1166:       sprintf(temp, "(x, y): (%d, %d)  red: %d green: %d blue: %d\n",
1167:  	     x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
1168:  	     (*img_cur).data[VSIZE - y][x].green,
1169:  	     (*img_cur).data[VSIZE - y][x].blue);
1170:       setCRect(0, 0, 200, 12, black);
1171:       glColor3f(1.0, 0.0, 0.0);
1172:       drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
1173:       glFlush();
1174:    }
1175:  }
1176:  
1177:  void buffer()
1178:  {
1179:     detect_corners(img_cur);
1180:  
1181:     glutPostRedisplay();
1182:  }
1183:    
1184:  /* =================================================================
1185:   * init - initializes graphics viewport
1186:   *
1187:   * You should not have to change this function for the first few
1188:   * projects we have. It will become more important when we move to
1189:   * 3D graphics.
1190:   * ----------------------------------------------------------------- */
1191:  void init (void)
1192:  {
1193:  /*
1194:   * select clearing color - white
1195:   */
1196:     glClearColor (1.0, 1.0, 1.0, 0.0);
1197:  
1198:  /*
1199:   * initialize viewport values
1200:   */
1201:     glMatrixMode(GL_PROJECTION);
1202:     glLoadIdentity();
1203:     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
1204:  
1205:     /*add menus*/
1206:     glutCreateMenu(menu);
1207:     glutAddMenuEntry("Restart", RESTART);
1208:     glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
1209:     glutAddMenuEntry("2x C. Corr.", X2_C_CORR);
1210:     glutAddMenuEntry("new corr", NEW_CORR);
1211:     glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
1212:     glutAddMenuEntry("moravec", MORAVEC);
1213:     glutAddMenuEntry("corners", CORNERS);
1214:     glutAttachMenu(GLUT_RIGHT_BUTTON);
1215:  
1216:  }
1217:   
1218:  int main(int argc, char** argv)
1219:  {
1220:     char PGMfileName[MAX_FILE_LENGTH];
1221:     
1222:     int WindowID;
1223:  
1224:     int i;  /*looping variable*/
1225:      
1226:     /*parse the command line*/  
1227:     if(argc == 1)
1228:     {
1229:        printf("To few parameters.\n");
1230:        printf("Usage: research <file.pgm>\n");
1231:        exit(1);
1232:     }
1233:     else if(argc == 2)
1234:        strcpy(PGMfileName, argv[1]);
1235:     else
1236:     {
1237:        printf("To many parameters.\n");
1238:        printf("Usage: research <file.pgm>\n");
1239:        exit(1);
1240:     }
1241:  /*
1242:   * Read in image file. - note: sets our global values, too.
1243:   * ----------------------------------------------------------------- */
1244:               
1245:     img0 = (PGMImage*) malloc(sizeof(PGMImage));
1246:     getPGMfile(PGMfileName, img0);
1247:     HSIZE = (*img0).width;
1248:     VSIZE = (*img0).height;
1249:     MVAL = (*img0).maxVal;
1250:  
1251:     img_cur = img0; /*VERY IMPORTANT to set this*/
1252:              
1253:     /*allocate memory for second image*/
1254:     img1 = (PGMImage*) malloc(sizeof(PGMImage));
1255:     memcpy(img1, img0, sizeof(PGMImage));
1256:     /*(*img1).width = HSIZE;
1257:     (*img1).height = VSIZE;
1258:     (*img1).maxVal = 255;*/
1259:               
1260:     img2 = (PGMImage*) malloc(sizeof(PGMImage));
1261:     memcpy(img2, img0, sizeof(PGMImage));
1262:  
1263:     memset(corner1, 0, sizeof(coord) * MAX_CHAINS);
1264:     memset(corner2, 0, sizeof(coord) * MAX_CHAINS);
1265:     memset(corner3, 0, sizeof(coord) * MAX_CHAINS);
1266:     memset(corner4, 0, sizeof(coord) * MAX_CHAINS);
1267:  
1268:  /*
1269:   * Initialize the glut package.
1270:   * ----------------------------------------------------------------- */
1271:     glutInit(&argc, argv);
1272:  
1273:     glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1274:  
1275:  /*           
1276:   * Define a new window (its size, position and title).
1277:   * ----------------------------------------------------------------- */
1278:        glutInitWindowSize (HSIZE, VSIZE);  /*size*/
1279:        glutInitWindowPosition (10, 10);    /*position*/
1280:        WindowID = glutCreateWindow (PGMfileName); /*title*/
1281:        glutSetWindow(WindowID);
1282:        glutDisplayFunc(color);
1283:        
1284:  /*  
1285:   * Call our init function to define viewing parameters.
1286:   * ----------------------------------------------------------------- */
1287:     init ();
1288:     
1289:     glutMouseFunc(mouse);
1290:  #ifdef BUFFERED
1291:     glutIdleFunc(buffer);
1292:     printf("idle engaged\n");
1293:  #endif
1294:     glutKeyboardFunc(keyboard); 
1295:     glutMainLoop();
1296:  
1297:  /*  
1298:   * When we reach here, we've left the event loop and are ready to
1299:   * exit.
1300:   * ----------------------------------------------------------------- */
1301:     return 0;
1302:  }
1303:  
1304:  
1305:  
1306:  
1307:  
1308:  
1309:  
1310:  
1311:  
1312:  
1313:  
1314:  
1315: