#include <stdio.h>
#include <graphinc.h>
#include <signal.h>

#define  BYTESPERLINE  128
#define  YZERO  400
#define  XZERO  550
#define  XLINE  530
#define  FL  8
#define  LL  16
#define  IOSCALE  3
#define  GMAX  256
#define  XDIV  1
#define  TABLEWIDTH  256
#define  MXSC  0
#define  MYSC  2
#define	XPIXELS	688
#define	YPIXELS	512

#define  MAPFILE  "map.dat"

#define  grey(x)  (x+(x<<5)+(x<<10))
#define  limity(y)  {if(y>=bright) y=bright-1; if (y<=dark) y=dark+1;}
#define  limitx(x)  {if(x>=GMAX) x=GMAX-1; if (x<0) x=0;}

short bright=255;
short dark=0;
short xoff = 0;
short yoff = 0;
short colourm[TABLEWIDTH] ;
char progname[] = "retouch";

FILE *fp;

extern abort(), stop();

void write_y();

main()
{
  signal(SIGBUS,abort);
  signal(SIGSEGV,abort);
  signal(SIGINT,stop);

  clearhist();
  startup();
  fprintf(stderr,"Middle button to pick, left to save and exit, ^Y to abort.\n");
  alterall();
  dumpmap();
  clearhist();
}


 
error(s)
char *s;
{
  fprintf(stderr,"%s: %s\n",progname,s);
  exit(1);
}



abort()
{
  clearhist();
  error("Lack of mouse and/or graphics board");
}

stop()
{
  clearhist();
  exit(1);
}



readmap()
{
  short *p,i;
  if((fp = fopen(MAPFILE,"r")) == NULL)
  {
    linmap();
    return(0);
  }
  fprintf(stderr,"reading map file\n");
  for (i=0,p=colourm;i<TABLEWIDTH;i++)
    *p++ = 0377&getc(fp);
}



dumpmap()
{
  short *p,i;
  fprintf(stderr,"dumping map\n");
  if((fp = fopen(MAPFILE,"w")) == NULL)
    error("can't access map file");
  for (i=0,p=colourm;i<TABLEWIDTH;i++)
    putc((*p++)&0377,fp);
}


linmap()
{
  short i;

  for (i=0; i<TABLEWIDTH; i++)
    colourm[i] = i;
}



clearhist()
{
  short i,j,xs,xw;
  char *p;

  /* clear space for histogram */
  Colour(dark);
  xs=XLINE>>3;
  xw = (XPIXELS>>3)+1-xs;
  for (i=YZERO-TABLEWIDTH;i<=YZERO;i++)
  {
    p=frame + i*BYTESPERLINE + xs;
    for (j=0; j++ <xw;)
      *p++ =0377;
  }

  /* clear text */

  write_y( 0 );

}


startup()
{
  short i,c;

  Offset(0,0);
  Enable(0177777);

  readmap();

  /* copy ColourMap buffer into ColourMap */
  for (i=0;i<bright;i++)
  {
    c = colourm[i] >> IOSCALE;
    ColourMap[i*2+1] = grey(c);
    showg(i,bright);
  }
    c= (TABLEWIDTH>>IOSCALE)-1;
    ColourMap[bright*2+1] = grey(c);

  /* draw some cosmetic lines. */
  hline(0,bright,XPIXELS-XLINE);
  hline(0,dark,XZERO-XLINE);
  hline(TABLEWIDTH-1,bright,XPIXELS-XLINE);
  hline(TABLEWIDTH-1,dark,XZERO-XLINE);
}


showg(i,c)
{
  short v,j;

  v=XZERO + ((colourm[i])>>XDIV);
  Colour(c);
  j=YZERO-i;
  Plot(v,j);
}



change(i,v)
{
  showg(i,dark);
  colourm[i]=v;
  v = v>>IOSCALE;
  ColourMap[i*2+1]=grey(v);
  showg(i,bright);
}



changeint(i,j,vi,vj)
{
  short k,v,vd,d;
  long vb;

  if (j<i) {
    k=i; i=j; j=k;
    k=vi; vi=vj; vj=k;
  }

  d=(j-i)<<1;
  vd=(vj-vi)<<1;

  if (d==0)
  {
    change(j,vj);
    return(0);
  }

  vb=vi*d+(j-i);
  for (k=i;k<=j;k++)
  {
    v = vb/d;
    change(k,v);
    vb = vb+vd;
  }
}


hline(y,c,l)
{
  short i;

  Colour(c);
  for (i=XLINE+l;i>XLINE;--i)
    Plot(i,YZERO-y);
}


cursory(y,l)
short *y;
{

  static short yc = 0;

  *y = -(MouseY>>MYSC) - yoff;
  limity(*y);

  if (*y!=yc)
  {
    hline(yc,dark,LL);
    hline(*y,bright,l);
    write_y(*y);
    yc = *y;
  }
}


xread(x)
short *x;
{
  char new;
  static short xc=0;

  new=0;
  *x = (MouseX>>MXSC) - xoff;
  limitx(*x);
  if (*x!=xc)
  {
    new=1;
    xc = *x;
  }
  return(new);
}


alterall()
{
  short first, last, vi, vj;

  first = 1;

  while ((MouseButtons&0377)!=1) 
  {
    yoff = -first - (MouseY>>MYSC);
    while((MouseButtons&0377)!=2)
    {
      if ((MouseButtons&0377)==1)
        return(0);
      cursory(&first,FL);
    }
    vi = colourm[first];

    while((MouseButtons&0377)==2) ;

    hline(first,bright,LL);
    while ((MouseButtons&0377)!=2)
      cursory(&last,LL);

    xoff = (MouseX>>MXSC) - colourm[last];
    xread(&vj);
    changeint(first,last,vi,vj);

    while ((MouseButtons&0377)==2) {
      if (xread(&vj))
        changeint(first,last,vi,vj);
    }

    hline(last,dark,LL);
    hline(last,bright,FL);
    first = last;
  }
}

void write_y( y ) /* writes integer y at ( x_text, y_text ) */
                  /* if y = 0 just clears text */
int y;
{
   static int x_text = 520;       /* text x position */
   static int y_text = 100;       /* text y position */
   static char space[ 5 ] = "";   /* space to store text */

   char *text;

   /* clear old text */

   Colour( Black );
   Fill( x_text, y_text, x_text + 27, y_text + 11 );

   /* write new text */

   if ( y != 0 )
   {
      Colour( bright );
      Textat( x_text, y_text );
      text = space;

      if ( y < 10 ) 
         sprintf( text, "  %d", y );
      else if ( y < 100 )
         sprintf( text, " %d", y );
      else
         sprintf( text, "%d", y );

      while (*text) ShowSymbol(*text++); /* write new text */
   }
}
