/* rubber1gl.c   basic rubber band for shape        */
/* Draw rectangle. left mouse down=first point      */
/* Drag to second point. left mouse up=final point  */
/* right mouse changes color of first figure area   */

#include <GL/glut.h>

static int winWidth = 500;
static int winHeight = 500;
static int tracking = 0; /* left button down, sense motion */
static int startX = 0;
static int startY = 0;
static int currentX = 0;
static int currentY = 0;
static int num_fig = 0; /* number of figures to draw */
static int select = 0;  /* the currently selected figure index */

typedef struct{int kind; int x0; int y0; int x1; int y1;
               float r; float g; float b; float width;}  fig;
static fig figure[100]; /* list of figures to draw */

void rubberRect(int x0, int y0, int x1 , int y1)
{ /* can apply to all figures */
  /* draw a rubber rectangle, mouse down, tracks mouse */
  glLineStipple(1,0xF00F);
  glEnable(GL_LINE_STIPPLE);
  glLineWidth(1.0);
  glColor3f(0.0,0.0,0.0);
  glBegin(GL_LINE_LOOP); 
    glVertex2f(x0, y0);
    glVertex2f(x0, y1);
    glVertex2f(x1, y1);
    glVertex2f(x1, y0);
  glEnd();
  glDisable(GL_LINE_STIPPLE);
}

/* one of many possible figures, kind=1 */
void drawRect(fig rect)
{
  /* draw a figure, rectangle */
  glLineWidth(rect.width);
  glColor3f(rect.r, rect.g, rect.b);
  glBegin(GL_LINE_LOOP); 
    glVertex2f(rect.x0, rect.y0);
    glVertex2f(rect.x0, rect.y1);
    glVertex2f(rect.x1, rect.y1);
    glVertex2f(rect.x1, rect.y0);
  glEnd();
}

void pick(int x, int y)
{
  int i;
  float t;
  
  /* search figures in list, select */
  for(i=0; i<num_fig; i++)
  {
    if(figure[i].x0 < figure[i].x1)
      if(x<figure[i].x0 || x>figure[i].x1) continue;
    if(figure[i].x1 < figure[i].x0)
      if(x<figure[i].x1 || x>figure[i].x0) continue;
    if(figure[i].y0 < figure[i].y1)
      if(y<figure[i].y0 || y>figure[i].y1) continue;
    if(figure[i].y1 < figure[i].y0)
      if(y<figure[i].y1 || y>figure[i].y0) continue;
    /* select here by just changing color */
    figure[select].r = 1.0;
    figure[select].g = 0.0;
    select = i;
    figure[select].r = 0.0;
    figure[select].g = 1.0;
    break;
  }
  glutPostRedisplay();
}

void mouseMotion(int x, int yn)
{
  int y; /* invert via winHeight */
  if(tracking)
  {
    y = winHeight-yn;
    currentX = x;
    currentY = y;
  } 
  glutPostRedisplay();
}

void startMotion(int x, int y)
{
  tracking = 1;
  startX = x;
  startY = y;
  currentX = x;
  currentY = y; /* start zero size, may choose to ignore later */
  glutPostRedisplay();
}

void stopMotion(int x, int y)
{
  tracking = 0; /* no more rubber_rect */

  /* save final figure data for 'display' to draw */
  currentX = x;
  currentY = y;
  figure[num_fig].kind = 1; /* just rectangles here */
  figure[num_fig].x0 = startX;
  figure[num_fig].y0 = startY;
  figure[num_fig].x1 = currentX;
  figure[num_fig].y1 = currentY;
  figure[num_fig].r = 1.0;
  figure[num_fig].g = 0.0;
  figure[num_fig].b = 0.0;
  figure[num_fig].width = 2.0;
  num_fig++;
  glutPostRedisplay();
}

void mouseButton(int button, int state, int x, int yn)
{
  int y; /* inverted by winHeight */

  y=winHeight-yn;

  if(button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) pick(x, y);
  
  if(button==GLUT_LEFT_BUTTON)
  {
    if(state==GLUT_DOWN) startMotion(x, y);
    if(state==GLUT_UP)   stopMotion (x, y);
  }
}

void reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  winWidth = w;
  winHeight = h;
  glutPostRedisplay();
}

void display(void)
{
  int i;
  
  glClear(GL_COLOR_BUFFER_BIT);
  if(tracking) rubberRect(startX, startY, currentX, currentY);

  /* draw figures per list */
  for(i=0; i<num_fig; i++)
  {
    /* should do switch on figure[i].kind */
    drawRect(figure[i]);
  }
  glFlush();  
}

int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB);
  glutInitWindowSize(winWidth, winHeight);
  glutInitWindowPosition(100,100); 
  glutCreateWindow(argv[0]);
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutMouseFunc(mouseButton);
  glutMotionFunc(mouseMotion);
  gluOrtho2D(0.0, (GLfloat)winWidth, 0.0, (GLfloat)winHeight);
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glutMainLoop();
  return 0;
}

