
/* R. Eastman Sept. 1997 */
/* rubberband.c */

/* This program is to illustrate the use of mouse and menu in glut. Nothing fancy, just 
experiments to illustrate the concepts and get a basic polyline input mechanism in place */


#include <GL/glut.h>
#include <stdio.h>

#define INPUT_MODE  0
#define EDIT_MODE 1
#define DELETE_MODE 2
#define mabs(a)  ((a) < 0 ? (-(a)) : (a))

int NPts = 0;
int Pts[20][2];
int State = INPUT_MODE;
int EditPt = -1;
char *Name[3] = { "Input", "Edit", "Delete" };

void
bitmap_output(int x, int y, char *string, void *font)
{
  int len, i;

  glRasterPos2f(x, y);
  len = (int) strlen(string);
  for (i = 0; i < len; i++) {
    glutBitmapCharacter(font, string[i]);
  }
}


void
reshape(int w, int h)
{
  glViewport(0, 0, w, h);       /* Establish viewing area to cover entire window. */
  glMatrixMode(GL_PROJECTION);  /* Start modifying the projection matrix. */
  glLoadIdentity();             /* Reset project matrix. */
  glOrtho(0, w, 0, h, -1, 1);   /* Map abstract coords directly to window coords. */
  glScalef(1, -1, 1);           /* Invert Y axis so increasing Y goes down. */
  glTranslatef(0, -h, 0);       /* Shift origin up to upper-left corner. */
}

void
display(void)
{
  int I;
  char Str[40];
  
  glClear(GL_COLOR_BUFFER_BIT);
  glColor3f( 1.0,1.0,1.0);
  glPointSize(1.0);
  glBegin(GL_LINE_STRIP);
  	for (I = 0; I < NPts; I++)
  	    glVertex2i(Pts[I][0], Pts[I][1]); 
  glEnd();
  
  glColor3f( 1.0, 0.0, 0.0);
  glPointSize(3.0);
  glBegin(GL_POINTS);
  	for (I = 0; I < NPts; I++)
  	    glVertex2i(Pts[I][0], Pts[I][1]); 
  glEnd();
  
  bitmap_output(40,35, Name[State], GLUT_BITMAP_TIMES_ROMAN_24);
   
  if (EditPt != -1 && State == EDIT_MODE) {
    glColor3f( 0.0, 1.0, 0.0);
    glBegin(GL_POINTS);
      glVertex2i(Pts[EditPt][0], Pts[EditPt][1]);
    glEnd();
    sprintf(Str, "(%3d,%3d)", Pts[EditPt][0], Pts[EditPt][1]);
    bitmap_output(150, 35, Str ,
    GLUT_BITMAP_TIMES_ROMAN_24);
    }
  
 
  
}

void 
mousept(int btn, int state, int x, int y) {

int I;

switch (State) {

  case INPUT_MODE:
   if ((btn != GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) {		 
 	     Pts[NPts][0] = x;
	     Pts[NPts][1] = y;
	     NPts ++;
 	     }
   break;
  case EDIT_MODE:
     {
       EditPt = -1;
       for (I = 0; I < NPts; I++)
           if ((mabs(x-Pts[I][0]) <= 10) && (mabs(y-Pts[I][1]) <= 10))
               EditPt = I;
     }
     break;
  case DELETE_MODE:
     {
      EditPt = -1;
      for (I=0; I < NPts; I++)
          if ((mabs(x-Pts[I][0]) <= 10) && (mabs(y-Pts[I][1]) <= 10))
               EditPt = I;
      if (EditPt > -1) {
          NPts--;
          for (I=EditPt; I < NPts; I++) {
               Pts[I][0] = Pts[I+1][0];
               Pts[I][1] = Pts[I+1][1];
               }
         }
     /*  State = INPUT_MODE;*/
      }
   
  }
 glutPostRedisplay();
}

void MovePt(int x, int y) {
  
   if (State == EDIT_MODE)
      if (EditPt > -1) {
       Pts[EditPt][0] = x;
       Pts[EditPt][1] = y;
       glutPostRedisplay();
       }
}

void HandleMenu(int Choice) {


     if (Choice == 1) { State = INPUT_MODE; EditPt = -1; }
else if (Choice == 2) { State = EDIT_MODE; }
else if (Choice == 3) { State = INPUT_MODE; 
                        NPts = 0;
                        EditPt = -1;
                        glClear(GL_COLOR_BUFFER_BIT); 
                      }
else if (Choice == 4) { State = DELETE_MODE; }
    glutPostRedisplay();
}

void InitMenus(void) {

   glutCreateMenu(HandleMenu);
   glutAddMenuEntry("Input pts", 1);
   glutAddMenuEntry("Edit pts", 2);
   glutAddMenuEntry("Clear pts", 3);
   glutAddMenuEntry("Delete pt", 4);
   glutAttachMenu(GLUT_RIGHT_BUTTON);
   
}


int
main(int argc, char **argv)
{

  glutInit(&argc, argv);
  glutCreateWindow("openGL experiment");
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutMouseFunc(mousept);
  glutMotionFunc(MovePt);
  InitMenus();
  glutMainLoop();
  return 0;             /* ANSI C requires main to return int. */
}
