/* PROGRAM DISPLAY */
/* ---------------------------------------------------- */
/*                                                      */
/*   REMAPP PC Remote Sensing Image Processing System   */
/*                     Version 1.20                     */
/*                                                      */
/*  MS-DOS  VGA graphics  320 pixels by 200 scanlines   */
/*  Displays images in 64 shades of gray or 256 colors  */
/*                                                      */
/*                   by K. Eric Livo                    */
/*                                                      */
/*           United States Geological Survey            */
/*  Branch of Geophysics - Remote Sensing Lab, Denver   */
/*                                                      */
/* ---------------------------------------------------- */

#include <fcntl.h>   /*  used in function (subroutine)  diskio  */
#include <io.h>      /*  used in diskio  */
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <graph.h>
#include <malloc.h>
#include <process.h>
#include <math.h>
void diskio(int op2, int *fd, unsigned char *ibuf, long *fcb);
void display();
void lutsint();
void dispimg();
void cursor();
void graphics();
void gadd();
void gsubtract();
void irestore();
void remappgraphics();
void dwindow();
void phelp();
void plane();
void clutsint();
void cdispimg();
void gpal(char key);
void resetpal();
void resetcpal();
void tempexit();
void gzoom();
void astretch();
void splot();
void yplot();
void sclose();
void scatter();
void freq_hist();
void freq_histib();
void lnparse(int);
void clnparse();
void freqgraph();
void overlay();
void shadow();

int crline=99,crpixel=159;
int iline,linemax=200,pixmax=320;
long pal[256], cpal[256], pal0, pal7, cpal0, cpal7;
long fcbg[129];             /*  note - make dimension as fcb[128+1]  */
			    /*  so fcb numbers match DISKIO.FTN      */

unsigned char ibufg[16384], message[79];
int op, fdg;

long lnans[4];              /*  parsed long integer line input  */
unsigned char clnans[81];   /*  unparsed string input           */

long gcolor[11];            /*  graphic overlay variables  */
int glevel,goper[11],gdnl[11],gdnh[11];
int winx1=0,winy1=0,winx2=319,winy2=199;

int vmode=1;  /* vmode=1: initializes graphics mode & gray palette  */
	      /* within subroutine dispimg                          */
int wmode=0;  /* wmode=1: enables prompt window (data entery) within    */
	      /* subroutine dispimg; ie: diskio scanline - pixel subset */
int loop = 0;
int pcolor=0,ipcolor[7];  /*  pcolor  b&w=0,  color=1  */
int zpower=1, lnorg, pixorg, qimage[7], qlnorg[7], qpixorg[7]; /* power and upper left image coord */
int pfile=0;  /* pfile=0 - close file in dispimg(); 1 - close in <D W E> */
int plotrglw=0, plotrghi=100;
unsigned char far *buffer;
unsigned char *cross;
unsigned char *crossimg;
unsigned char far *bimage1;
unsigned char far *bimage2;
unsigned char far *bimage3;
unsigned char far *bimage4;
unsigned char far *bimage5;
unsigned char far *bimage6;


main()
{
   char key=' ';
   _wrapon(_GWRAPON);

   /*  press escape <esc> key to exit program  */

   for(glevel=0;glevel<11;glevel++)
      {
      goper[glevel]=0;
      }
   /*  initiallize image buffer checks  */
   for(glevel=0; glevel<7; glevel++)
      {
      qimage[glevel]=0;
      }

   iline=0;
   lutsint();
   clutsint();
   dispimg();

   /*  create image buffers  ,for plane subroutine  */
   bimage1=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage1 == (char far *)NULL)
      {
      exit(-1);
      }
   bimage2=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage2 == (char far *)NULL)
      {
      exit(-1);
      }
   bimage3=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage3 == (char far *)NULL)
      {
      exit(-1);
      }
   bimage4=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage4 == (char far *)NULL)
      {
      exit(-1);
      }
   bimage5=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage5 == (char far *)NULL)
      {
      exit(-1);
      }
   bimage6=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));
   if (bimage6 == (char far *)NULL)
      {
      exit(-1);
      }

/*  start main option selection menu  */
   _settextposition(1,1);
   while(key != 27)
   {
      key = getch();
      if(key == 0)
	 {
	 key = getch();
	 key = ' ';
	 }
      switch(key)
      {
	 case 'V':
	 case 'v':
	    if (pcolor == 0) astretch();
	    break;
	 case 'B':
	 case 'b':
	    resetpal();
	    break;
	 case 'K':
	 case 'k':
	    resetcpal();
	    break;
	 case '1':
	    if (qimage[1] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage1,_GPSET);
	       }
	    break;
	 case '2':
	    if (qimage[2] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage2,_GPSET);
	       }
	    break;
	 case '3':
	    if (qimage[3] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage3,_GPSET);
	       }
	    break;
	 case '4':
	    if (qimage[4] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage4,_GPSET);
	       }
	    break;
	 case '5':
	    if (qimage[5] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage5,_GPSET);
	       }
	    break;
	 case '6':
	    if (qimage[6] > 0)
	       {
	       gpal(key);
	       _putimage(0,0,bimage6,_GPSET);
	       }
	    break;
	 case 'I':
	 case 'i':
	    plane();
	    break;
	 case 'H':
	 case 'h':
	    phelp();
	    break;
	 case 'D':
	 case 'd':
	    if(pfile>0) sclose();
	    display();
	    break;
	 case 'C':
	 case 'c':
	    cursor();
	    break;
	 case 'G':
	 case 'g':
	    graphics();
	    break;
	 case 'A':
	 case 'a':
	    gadd();
	    break;
	 case 'S':
	 case 's':
	    gsubtract();
	    break;
	 case 'R':
	 case 'r':
	    irestore();
	    break;
	 case 'W':
	 case 'w':
	    dwindow();
	    break;
	 case 'M':
	 case 'm':
	    cdispimg();
	    break;
	 case 'E':
	 case 'e':
	    tempexit();
	    break;
	 case 'Z':
	 case 'z':
	    gzoom();
	    break;
	 case 'P':
	 case 'p':
	    splot();
	    break;
	 case 'Y':
	 case 'y':
	    yplot();
	    break;
	 case 'X':
	 case 'x':
	    scatter();
	    break;
	 case 'F':
	    freq_histib();
	    break;
	 case 'f':
	    freq_hist();
	    break;
	 case 'O':
	 case 'o':
	    overlay();
	    break;
	 case 'L':
	 case 'l':
	    shadow();
	    break;
      }
   }
   _setvideomode(_DEFAULTMODE);
}

void overlay()
{
   int dn;
   long density, denblue, dengrn, denred;
   long ovpal[256];

   ovpal[0] = 0L;

   for(dn=1; dn<128; dn++)
      {
      ovpal[dn] = (63L - (dn/2L))*65536L + (dn/2L)*256L;
      }
   for(dn=128; dn<256; dn++)
      {
      ovpal[dn] = (127L - (dn/2L))*256L + ((dn/2L)-64L);
      }
   _remapallpalette(&(ovpal[0]));
}

void astretch()
{
   int dn, pixel, alookup[256],hist[256];
   int dn2p=0, dn50p=0, dn98p=0;
   long coffset, total=0, sum=0;

   for (dn=0; dn < 256; dn++)
      {
      hist[dn] = 0;
      alookup[dn] = 0;
      }

   _getimage(0,0,319,199,bimage6);
   ipcolor[6] = pcolor;
   qimage[6] = zpower;
   qlnorg[6] = lnorg;
   qpixorg[6] = pixorg;

   _settextwindow(1,1,25,40);
   _clearscreen(_GWINDOW);

   /* calc alookup[new dn's  0 - 255] here */
   for (iline=0; iline < linemax; iline++)
      {
      for (pixel=0; pixel < pixmax; pixel++)
	 {
	 dn = bimage6[(iline * pixmax) + pixel + 4];
	 if (dn > 0 && dn < 255)
	    {
	    hist[dn] += 1;
	    total += 1;
	    }
	 }
      }

   for (dn=1; dn < 255; dn++)
      {
      sum = sum + hist[dn];
      if ((sum*100L)/total < 2L) dn2p = dn - 7;
      if ((sum*100L)/total < 50L) dn50p = dn;
      if ((sum*100L)/total < 99L) dn98p = dn;
      }
   if (dn2p < 0) dn2p = 0;

   for (dn=0; dn < dn2p; dn++)
      {
      alookup[dn] = 0;
      }
   for (dn=dn2p; dn < dn50p; dn++)
      {
      if (dn2p != dn50p) alookup[dn] = ((dn - dn2p) * 127) / (dn50p - dn2p);
      }
   for (dn=dn50p; dn < dn98p; dn++)
      {
      if (dn50p != dn98p) alookup[dn] = (((dn - dn50p) * 128) / (dn98p - dn50p)) + 127;
      }
   for (dn=dn98p; dn < 256; dn++)
      {
      alookup[dn] = 255;
      }

   for (iline=0; iline < linemax; iline++)
      {
      for (pixel=0; pixel < pixmax; pixel++)
	 {
	 coffset = (iline * pixmax) + pixel + 4;
	 dn = alookup[bimage6[coffset]];
	 _setcolor(dn);
	 _setpixel(pixel, iline);
	 }
      }
}

void gzoom()
{
   int dn, pixel, lncur, pixcur;
   long coffset;
   char key= ' ';

   _getimage(0,0,319,199,bimage6);
   ipcolor[6] = pcolor;
   qimage[6] = zpower;
   qlnorg[6] = lnorg;
   qpixorg[6] = pixorg;
   cursor();
   /*  set current cursor location */
   lncur = lnorg + crline/zpower;
   pixcur = pixorg + crpixel/zpower;
   zpower = zpower * 2;
   lnorg = lnorg + crline/zpower;
   pixorg = pixorg + crpixel/zpower;
   qimage[0] = zpower;
   qlnorg[0] = lnorg;
   qpixorg[0] = pixorg;
   crline = (lncur - lnorg) * zpower;
   crpixel = (pixcur - pixorg) * zpower;
   _clearscreen(_GWINDOW);
   for (iline=0; iline < linemax; iline++)
      {
      for (pixel=0; pixel < pixmax; pixel++)
	 {
	 coffset = ((((lnorg - qlnorg[6]) * qimage[6]) + (iline/2)) * pixmax) + ((pixorg - qpixorg[6]) * qimage[6]) + (pixel/2) +4;
	 dn = bimage6[coffset];
	 _setcolor(dn);
	 _setpixel(pixel, iline);
	 }
      }
}


void tempexit()
{
   unsigned char xmessage[130];

   if(pfile > 0) sclose();
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   _outtext("type: EXIT to return  <press any key>");
   getch();

/*  try to free up system memory for larger jobs  */
/*  to be done in later version  */
/*   free((char far *)buffer);   */
/*   free((char far *)bimage6);  */
/*   qimage[6] = 0;              */

   _setvideomode(_DEFAULTMODE);
   system("COMMAND");
	     /*  Temp exit to system  */
   /*  -------------------------------------------*/
	     /*   Return to Display   */
   _setvideomode(19);      /*  VGA graphics 256 colors  */

/*   bimage6=(char far *)malloc((unsigned int) _imagesize(0,0,319,199));  */
/*   if (bimage6 == (char far *)NULL)  */
/*      {                              */
/*      exit(-1);                      */
/*      }                              */

   resetpal();
   _settextwindow(1,1,25,40);
   _settextposition(1,1);
   _settextcolor(255);
   _outtext("   REMAPP PC Image Processing System");
   sprintf(xmessage,"\n\n Welcome back, load image from: \n    <1> - <5>  Image Buffers\n    <D>        DISPLAY\n or \n    <W>        WINDOW");
   _outtext(xmessage);
}

void gpal(char key)
{
   zpower = qimage[key-48];
   lnorg = qlnorg[key-48];
   pixorg = qpixorg[key-48];
   if (pcolor != ipcolor[key-48])
      {
      pcolor=ipcolor[key-48];
      _settextwindow(1,1,25,40);
      _clearscreen(_GWINDOW);
      if (pcolor == 1)
	 resetcpal();
      else
	 resetpal();
      }
}

void display()
{
   if (pcolor == 1) resetpal();
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(2,2,7,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   iline=0;
   winx1=0;
   winy1=0;
   winx2=319;
   winy2=199;
   qimage[0] = 1;
   qlnorg[0] = 0;
   qpixorg[0] = 0;
   zpower = qimage[0];
   lnorg = qlnorg[0];
   pixorg = qpixorg[0];
   dispimg();
   _remappalette(0,pal0);
   _remappalette(7,pal7);
}

void lutsint()
{
   int num;

   for (num=0;num<64;num++)
      {
      pal[num*4]=65536*num+256*num+num;
      pal[num*4+1]=pal[num*4];
      pal[num*4+2]=pal[num*4];
      pal[num*4+3]=pal[num*4];
      }
   pal0=pal[0];
   pal7=pal[7];
}

void dispimg()
{
   int dn,pixel,pixel16,lns;

   /*  open input file - DISKIO  */
   op=0;
   diskio(op,&fdg,ibufg,fcbg);
   if (fcbg[1] < 0) goto direturn;

   /*  end of DISKIO open input  */

   if (vmode == 1)
      {
      if (_setvideomode(19))
	 {
	 _remapallpalette(&(pal[0]));
	 }
      else
	 {
	 printf("VGA mode 19 not available \n");
	 exit(-1);
	 }
      }

   vmode = 0;

   if(wmode == 1)  /*  if=1, then windowing an image  */
      {
      _putimage(0,0,buffer,_GPSET);
      free((char far *)buffer);
      wmode=0;
      }
   else
      {
      _settextwindow(1,1,25,40);
      _clearscreen(_GWINDOW);
      }

   _setviewport(winx1,winy1,winx2,winy2);

   _remappalette(0,pal0);
   _remappalette(7,pal7);

   while(iline < linemax)              /*  fcbg[3]=linemax  */
      {
      /*  DISKIO  Read a record  */
      op=9;
      diskio(op,&fdg,ibufg,fcbg);
      /*  end DISKIO  READ  */

      if(iline != linemax)
	 {
	 for(pixel=0; pixel < pixmax; pixel++)    /* fcbg[2]>=pixmax */
	    {
	    dn=ibufg[pixel];          /*  read 8 bits/pixel data   */
	    if(fcbg[25] == 16)        /*  read 16 bits/pixel data  */
	       {
	       pixel16 = pixel*2;
	       dn=(ibufg[pixel16] + ibufg[pixel16+1]*256) / 100;
	       if(dn > 255) dn=255;   /* note 16 bit dn max 25,500 */
	       }
	    _setcolor(dn);
	    _setpixel(pixel,iline);
	    }
	 }
      iline++;
      }
   /* DISKIO close image file */
   if(pfile == 0)
      {
      op=6;
      diskio(op,&fdg,ibufg,fcbg);
      }
   /* end close */

   /* reset graphics window  (origin and diagonal corner) */
   winx1=0;
   winy1=0;
   winx2=319;
   winy2=199;
   _setviewport(winx1,winy1,winx2,winy2);
   /* reset full screen (diskio) access */
   linemax=200;
   pixmax=320;

direturn:
;
}


void scatter()
{
   int xpix, ypix, pixel;

   /*  if image buffers are loaded  */

   if (qimage[1] > 0 && qimage[2] > 0)
      {

      /*  plot scatter  */
      _setcolor(255);
      _settextwindow(1,1,25,40);
      _clearscreen(_GWINDOW);
      _moveto(100,22);
      _lineto(100,150);
      _lineto(228,150);
      for(iline=0; iline < linemax; iline++)
	 {
	 for(pixel=0; pixel < pixmax; pixel++)
	    {
	    ypix=bimage1[(iline*pixmax)+pixel+4]/2;
	    xpix=bimage2[(iline*pixmax)+pixel+4]/2;
	    _setpixel(100+xpix,150-ypix);
	    }
	 }
      }
}


void freq_hist()
{
/*  display histogram  (screen)  */

   unsigned long freqint[256], highdn;
   int dn, fsl, fpix;

   /*  zero frequency interval array  */
   for (dn = 0; dn < 256; dn++)
      {
      freqint[dn] = 0;
      }
   highdn=1;

   /*  generate dn interval frequency - dn's from screen image  */
   for (fsl = 0; fsl < linemax; fsl++)
      {
      for (fpix = 0; fpix < pixmax; fpix++)
	 {
	 dn = _getpixel(fpix,fsl);
	 freqint[dn]++;
	 }
      }

   /*  scale histogram plot for screen  */
   for (dn = 0; dn < 256; dn++)
      {
      if(freqint[dn] > highdn) highdn = freqint[dn];
      }
   for (dn = 0; dn < 256; dn++)
      {
      freqint[dn] = (freqint[dn] * 100) / highdn;
      }

   /* plot histogram  */
   freqgraph();
   for (dn = 0; dn < 256; dn++)
      {
      _setpixel(30 + dn, 150 - freqint[dn]);
      }
}


void freqgraph()
{

   int freqplot;

   /*  clear screen  */
   _setcolor(255);
   _settextwindow(1,1,25,40);
   _clearscreen(_GWINDOW);

   _moveto(30,51);
   _lineto(30,154);
   _moveto(30,150);
   _lineto(285,150);

   for (freqplot = 40; freqplot < 285; freqplot+=10)
      {
      _moveto(freqplot,146);
      _lineto(freqplot,154);
      }
}


void freq_histib()
{
/*  display histogram  (image buffers)  */

   unsigned long freqint[256], highdn;
   int dn, fsl, fpix, fhst;

   /*  clear - display graph box  */
   freqgraph();

   /*  start image buffer loop  */
   for (fhst = 1; fhst < 7; fhst++)
      {
      if (qimage[fhst] > 0)
	 {
	 /*  zero frequency interval array  */
	 _setcolor(255 - fhst);
	 for (dn = 0; dn < 256; dn++)
	    {
	    freqint[dn] = 0;
	    }
	 highdn=1;

	 /*  generate dn interval frequency - dn's from image buffer  */
	 for (fsl = 0; fsl < linemax; fsl++)
	    {
	    for (fpix = 0; fpix < pixmax; fpix++)
	       {
	       switch(fhst)
		  {
		  case 1:
		     dn = bimage1[(fsl * pixmax) + fpix + 4];
		     break;
		  case 2:
		     dn = bimage2[(fsl * pixmax) + fpix + 4];
		     break;
		  case 3:
		     dn = bimage3[(fsl * pixmax) + fpix + 4];
		     break;
		  case 4:
		     dn = bimage4[(fsl * pixmax) + fpix + 4];
		     break;
		  case 5:
		     dn = bimage5[(fsl * pixmax) + fpix + 4];
		     break;
		  case 6:
		     dn = bimage6[(fsl * pixmax) + fpix + 4];
		     break;
		  }
	       freqint[dn]++;
	       }
	    }

	 /*  scale histogram plot for screen  */
	 for (dn = 0; dn < 256; dn++)
	    {
	    if(freqint[dn] > highdn) highdn = freqint[dn];
	    }
	 for (dn = 0; dn < 256; dn++)
	    {
	    freqint[dn] = (freqint[dn] * 100) / highdn;
	    }

	 /* plot histogram  */
	 for (dn = 0; dn < 256; dn++)
	    {
	    _setpixel(30 + dn, 150 - freqint[dn]);
	    }
	 }
      }
}



void splot()
{
   long fileslcr, plotsl, plotpix, dn16;
   int specpix[256], plotdn;

   if (pfile == 0)
      {
      pfile=1;
      display();
      plane();
      }

   cursor();
   if (zpower < 2)
      {
      plotsl = crline;
      plotpix = crpixel;
      }
   else
      {
      plotsl = lnorg + crline/zpower;
      plotpix = pixorg + crpixel/zpower;
      }

   /*  read spectra  */
   /*  file scanline of cursor band 1  */
   fileslcr = fcbg[5] + 1 + plotsl * (fcbg[7] + 1);
   op = 9;
   for (iline = 0; iline < fcbg[13]; iline++)
      {
      fcbg[14] = fileslcr + iline;
      diskio(op,&fdg,ibufg,fcbg);
      if (fcbg[25] == 8)
	 {
	 specpix[iline] = ibufg[plotpix];
	 }
      else
	 {
	 specpix[iline] = (ibufg[plotpix * 2] + ibufg[plotpix * 2 + 1] * 256)/100;
	 }
      }

   /*  plot spectra  */
   _setcolor(255);
   _settextwindow(1,1,25,40);
   plotpix = 10;
   _moveto(plotpix, 50);
   _lineto(plotpix, 150);
   _lineto(plotpix + (61 * 5), 150);

   /*  vert axis  */
   for (iline=0; iline<11; iline++)
      {
      _moveto(plotpix-4,150-(iline*10));
      _lineto(plotpix,150-(iline*10));
      }

   _moveto(plotpix-8,150);
   _lineto(plotpix,150);
   _moveto(plotpix-8,100);
   _lineto(plotpix,100);
   _moveto(plotpix-8,50);
   _lineto(plotpix,50);
   for(iline=0; iline < 10; iline++)
      {
      _moveto(plotpix-2,145-(iline*10));
      _lineto(plotpix,145-(iline*10));
      }

   /*  horz axis  */
   for(iline=0; iline<7; iline++)
      {
      _moveto(plotpix + (iline*10*5), 158);
      _lineto(plotpix + (iline*10*5), 150);
      }
   for(iline=0; iline<13; iline++)
      {
      _moveto(plotpix + (iline*5*5), 154);
      _moveto(plotpix + (iline*5*5), 150);
      }
   for(iline=0; iline<62; iline++)
      {
      _moveto(plotpix + (iline*5), 152);
      _lineto(plotpix + (iline*5), 150);
      }

   plotpix = plotpix + 5;
   plotdn = (specpix[0]/2 - plotrglw)*100 / (plotrghi - plotrglw);
   if (plotdn > 149) plotdn = 149;
   if (plotdn < 0) plotdn = 0;
   _moveto(plotpix, 150 - plotdn);

   for (iline = 1; iline < fcbg[13]; iline++)
      {
      plotpix = plotpix + 5;
      plotdn = (specpix[iline]/2 - plotrglw)*100 / (plotrghi-plotrglw);
      if (plotdn > 149) plotdn = 149;
      if (plotdn < 0) plotdn = 0;
      _lineto(plotpix, 150 - plotdn);
      }
}


void yplot()
{
   buffer=(char far *)malloc((unsigned int) _imagesize(0,184,319,199));
   if(buffer == (char far *)NULL)
   {
      exit(-1);
   }
   _getimage(0,184,319,199,buffer);
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   yloop1:
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      _outtext("% Reflectance: Low   High = ");
      lnparse(2);
      plotrglw = lnans[0];
      plotrghi = lnans[1];
      if ((plotrglw < 0) || (plotrghi > 100)) goto yloop1;
      if (plotrglw >= plotrghi) goto yloop1;

      _clearscreen(_GWINDOW);
      _putimage(0,184,buffer,_GPSET);
      free((char far *)buffer);
      _remappalette(0,pal0);
      _remappalette(7,pal7);
}


void sclose()
{
   pfile=0;
   op=6;
   diskio(op,&fdg,ibufg,fcbg);
}


void cursor()
{
   int lns,pix,dnc,cibuffer=0;
   long cioffset;
   char key=' ';

/*  start of options subroutines  */
   buffer=(char far *)malloc((unsigned int) _imagesize(0,191,319,199));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }

/*  create cross-hair image buffer  */
   cross=(char *)malloc((unsigned int) _imagesize(0,0,4,4));
   if (cross == (char far *)NULL)
      {
      exit(-1);
      }
   crossimg=(char far *)malloc((unsigned int) _imagesize(0,0,4,4));
   if (crossimg == (char far *)NULL)
      {
      exit(-1);
      }

   _getimage(0,191,319,199,buffer);

   /*  create cross-hair cursor  */
   _getimage(0,0,4,4,crossimg);
   _setcolor(0);
   for(lns=0;lns<5;lns++)
      {
      for(pix=0;pix<5;pix++)
	 {
	 _setpixel(pix,lns);
	 }
      }
   _setcolor(255);
   lns=2;
   for(pix=0;pix<5;pix++)
      {
      _setpixel(pix,lns);
      }
   pix=2;
   for(lns=0;lns<5;lns++)
      {
      _setpixel(pix,lns);
      }
   _getimage(0,0,4,4,cross);
   _putimage(0,0,crossimg,_GPSET);

   _settextcolor(255);
   _getimage(crpixel-2,crline-2,crpixel+2,crline+2,crossimg);
   _putimage(crpixel-2,crline-2,cross,_GOR);
   while(key != 13)
      {
      key = getch();
      if (key == 0) key = getch();
      _putimage(crpixel-2,crline-2,crossimg,_GPSET);
      if (key == 72)
	 crline = crline -1;
      if (key == 80)
	 crline = crline +1;
      if (key == 75)
	 crpixel = crpixel -1;
      if (key == 77)
	 crpixel = crpixel +1;
      if (key == 71)
	 {
	 crline = crline -1;
	 crpixel = crpixel -1;
	 }
      if (key == 79)
	 {
	 crline = crline +1;
	 crpixel = crpixel -1;
	 }
      if (key == 73)
	 {
	 crline = crline -1;
	 crpixel = crpixel +1;
	 }
      if (key == 81)
	 {
	 crline = crline +1;
	 crpixel = crpixel +1;
	 }
      if (key == 83)
	 {
	 crline=99;
	 crpixel=159;
	 }

      if (crline < 0) crline = 0;
      if (crpixel < 0) crpixel = 0;
      if (crline > linemax - 1) crline = linemax -1;
      if (crpixel > pixmax -1) crpixel = pixmax -1;

      if (key == 48) cibuffer=0;
      if ((key < 55) && (zpower < 2))
	 {
	 if ((key == 49) && (qimage[1] > 0)) cibuffer=1;
	 if ((key == 50) && (qimage[2] > 0)) cibuffer=2;
	 if ((key == 51) && (qimage[3] > 0)) cibuffer=3;
	 if ((key == 52) && (qimage[4] > 0)) cibuffer=4;
	 if ((key == 53) && (qimage[5] > 0)) cibuffer=5;
	 if ((key == 54) && (qimage[6] > 0)) cibuffer=6;
	 }

      if (cibuffer == 0)     /*  cibuffer 0 is screen image  */
	 {
	 dnc = _getpixel(crpixel,crline);
	 }
      else
	 {
	 /* start at byte 5 for col.0, row 0 */
	 cioffset = crline * pixmax + crpixel + 4;
	 if (cibuffer == 1) dnc = bimage1[cioffset];
	 if (cibuffer == 2) dnc = bimage2[cioffset];
	 if (cibuffer == 3) dnc = bimage3[cioffset];
	 if (cibuffer == 4) dnc = bimage4[cioffset];
	 if (cibuffer == 5) dnc = bimage5[cioffset];
	 if (cibuffer == 6) dnc = bimage6[cioffset];
	 }

      _getimage(crpixel-2,crline-2,crpixel+2,crline+2,crossimg);
      _putimage(crpixel-2,crline-2,cross,_GOR);

      _settextwindow(25,2,25,39);
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      if (zpower < 2)
	 {
	 sprintf(message,"Line=%d, Pixel=%d, DN=%d, Image%d",crline+1,crpixel+1,dnc,cibuffer);
	 }
      else
	 {
	 sprintf(message,"Line=%d, Pixel=%d, DN=%d",lnorg + crline/zpower +1, pixorg + crpixel/zpower +1,dnc);
	 }
      _outtext(message);
      _settextwindow(1,1,25,40);
      }      /*  loop if no <return>  */

   _putimage(crpixel-2,crline-2,crossimg,_GPSET);
   _putimage(0,191,buffer,_GPSET);
   free((char far *)buffer);
   free((char *)cross);
   free((char *)crossimg);
}

void graphics()
{
   int gnum, ans=0, temp1;
   char key=' ';

   buffer=(char far *)malloc((unsigned int) _imagesize(0,184,319,199));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }
   _getimage(0,184,319,199,buffer);
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   gloop1:
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      _outtext("Graphics Level: ");
      lnparse(1);
      glevel = lnans[0];
   if ((glevel < 0) || (glevel >10)) goto gloop1;
   while (ans < 1)
   {
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      _outtext("Graphics Color: ");
      key=getch();

      switch(key)
      {
	 case 'D':   /* dark */
	 case 'd':
	    gcolor[glevel]=0L;
	    ans = 1;
	    break;
	 case 'W':   /* white */
	 case 'w':
	    gcolor[glevel]=4144959L;
	    ans = 1;
	    break;
	 case 'Y':   /* yellow */
	 case 'y':
	    gcolor[glevel]=16191L;
	    ans = 1;
	    break;
	 case 'C':   /* cyan */
	 case 'c':
	    gcolor[glevel]=4144896L;
	    ans = 1;
	    break;
	 case 'M':   /* magenta */
	 case 'm':
	    gcolor[glevel]=4128831L;
	    ans = 1;
	    break;
	 case 'R':   /* red */
	 case 'r':
	    gcolor[glevel]=63L;
	    ans = 1;
	    break;
	 case 'G':   /* green */
	 case 'g':
	    gcolor[glevel]=16128L;   /* green */
	    ans = 1;
	    break;
	 case 'B':   /* blue */
	 case 'b':
	    gcolor[glevel]=4128768L;
	    ans = 1;
	    break;
      }
   }
   gloop2:
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      _outtext("DN's: Low  High = ");
      lnparse(2);
      gdnl[glevel] = lnans[0];
      gdnh[glevel] = lnans[1];
      if ((gdnh[glevel] < 0) || (gdnh[glevel] > 255)) goto gloop2;
      if ((gdnl[glevel] < 0) || (gdnl[glevel] > 255)) goto gloop2;
      if (gdnl[glevel] > gdnh[glevel]) goto gloop2;
   _clearscreen(_GWINDOW);
   goper[glevel]=2;
   _putimage(0,184,buffer,_GPSET);
   free((char far *)buffer);
   _remappalette(0,pal0);
   _remappalette(7,pal7);
}


void gadd()
{

   buffer=(char far *)malloc((unsigned int) _imagesize(0,184,319,199));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }
   _getimage(0,184,319,199,buffer);
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   _outtext("Graphics Level: ");
   lnparse(1);
   glevel = lnans[0];
   _clearscreen(_GWINDOW);
   _putimage(0,184,buffer,_GPSET);
   free((char far *)buffer);
   _remappalette(0,pal0);
   _remappalette(7,pal7);
   if ((glevel >=0) && (glevel <=10))
      {
      if(goper[glevel] == 2)
	 {
	 goper[glevel]=1;
	 remappgraphics();
	 }
      }
}


void gsubtract()
{

   buffer=(char far *)malloc((unsigned int) _imagesize(0,184,319,199));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }
   _getimage(0,184,319,199,buffer);
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   _outtext("Graphics Level: ");
   lnparse(1);
   glevel = lnans[0];
   _clearscreen(_GWINDOW);
   _putimage(0,184,buffer,_GPSET);
   free((char far *)buffer);
   _remappalette(0,pal0);
   _remappalette(7,pal7);
   if ((glevel >= 0) && (glevel <=10))
      {
      if(goper[glevel] == 1)
	 {
	 goper[glevel] = 2;
	 }
      }
   remappgraphics();
}


void irestore()
{
   if (pcolor == 0) resetpal();
   if (pcolor == 1) resetcpal();
}


void remappgraphics()
{
   int level,gdn;

   if (pcolor == 0)
      {
      _remapallpalette(&(pal[0]));
      pal0=pal[0];
      pal7=pal[7];
      }
   if (pcolor == 1)
      {
      _remapallpalette(&(cpal[0]));
      pal0=cpal[0];
      pal7=cpal[7];
      }
   for(level=0;level<11;level++)
      {
      if(goper[level] == 1)
	 {
	 for(gdn=gdnl[level];gdn<(gdnh[level]+1);gdn++)
	    {
	    _remappalette(gdn,gcolor[level]);
	    if(gdn==0) pal0=gcolor[level];
	    if(gdn==7) pal7=gcolor[level];
	    }
	 }
      }
}


void dwindow()
{
   if (pcolor == 1) resetpal();
   if (pfile > 0) sclose();

   /*  use cursor subroutine to get upper left and lower right coord's  */
   winloop:
      cursor();
      winx1 = crpixel;
      winy1 = crline;
      cursor();
      winx2 = crpixel;
      winy2 = crline;
   if ((winx1 > winx2) || (winy1 > winy2)) goto winloop;

   /*  set window for diskio subset query  */
   buffer = (char far *)malloc((unsigned int) _imagesize(0,0,319,55));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }
   _getimage(0,0,319,55,buffer);

   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(2,2,7,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   wmode=1;
   iline=0;
   dispimg();
   _remappalette(0,pal0);
   _remappalette(7,pal7);
}


void plane()
{
   int pnum=0;

   buffer=(char far *)malloc((unsigned int) _imagesize(0,184,319,199));
   if (buffer == (char far *)NULL)
      {
      exit(-1);
      }
   _getimage(0,184,319,199,buffer);
   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(24,2,24,39);
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   _outtext("Write Image to Buffer: ");
   lnparse(1);
   pnum = lnans[0];
   _clearscreen(_GWINDOW);
   _putimage(0,184,buffer,_GPSET);
   free((char far *)buffer);
   if ((pnum > 0) && (pnum < 7))
      {
      if(pnum == 1) _getimage(0,0,319,199,bimage1);
      if(pnum == 2) _getimage(0,0,319,199,bimage2);
      if(pnum == 3) _getimage(0,0,319,199,bimage3);
      if(pnum == 4) _getimage(0,0,319,199,bimage4);
      if(pnum == 5) _getimage(0,0,319,199,bimage5);
      if(pnum == 6) _getimage(0,0,319,199,bimage6);
      ipcolor[pnum] = pcolor;
      qimage[pnum] = zpower;
      qlnorg[pnum] = lnorg;
      qpixorg[pnum] = pixorg;
      }
   _remappalette(0,pal0);
   _remappalette(7,pal7);
}

void clutsint()
{
   int dn, dnr, dng, dnb;
   /*  generate color lookup table array  0 to 255  (color palette  */
   dn=-1;
   for (dnr=0; dnr < 64; dnr +=9)
      {
      for (dng=0; dng < 64; dng +=9)
	 {
	 for (dnb=0; dnb < 64; dnb +=21)
	    {
	    dn=dn+1;
	    cpal[dn]=65536*dnb + 256*dng + dnr;
	    }
	 }
      }
   cpal0=cpal[0];
   cpal7=cpal[7];
}

void cdispimg()
{
   int dn, dnr, dng, dnb, pixel;
   long coffset;

   if (((qimage[1] > 0) && (qimage[2] > 0)) && (qimage[3] > 0))
      {
      _settextwindow(1,1,25,40);
      _clearscreen(_GWINDOW);
      resetcpal();
      for (iline=0; iline < linemax; iline++)
	 {
	 for (pixel=0; pixel < pixmax; pixel++)
	    {
	    /*  red=(dn/32)*32, green=(dn/32)*4, blue=(dn/64)  */
	    coffset=iline*pixmax+pixel+4; /* start at byte 5 for col.0, row 0 */
	    dnr=bimage3[coffset]/32;
	    dng=bimage2[coffset]/32;
	    dnb=bimage1[coffset]/64;
	    /*  dnr, dng, and dnb truncate division to integers (above) */
	    dn=dnr*32 + dng*4 + dnb;
	    _setcolor(dn);
	    _setpixel(pixel,iline);
	    }
	 }
      }
}

void shadow()
{
   double incl, decl;
   float x, y, z;
   int dn, pixel;
   long coffset;

   if (((qimage[1] > 0) && (qimage[2] > 0)) && (qimage[3] > 0))
      {
      _remappalette(0,0L);
      _remappalette(7,4144959L);
      _settextcolor(7);
      _settextwindow(24,2,24,39);
      _clearscreen(_GWINDOW);
      _settextposition(1,1);
      _outtext("Enter sun inclination, azimuth: ");
      lnparse(2);
      incl = lnans[0];
      decl = lnans[1];
      _clearscreen(_GWINDOW);
      _settextwindow(1,1,25,40);
      _clearscreen(_GWINDOW);
      if(pcolor) resetpal();

      incl = 0.017453292*incl;
      decl = 0.017453292*decl;
      x = cos(incl)*sin(decl);
      y = cos(incl)*cos(decl);
      z = sin(incl);

      for (iline=0; iline < linemax; iline++)
	 {
	 for (pixel=0; pixel < pixmax; pixel++)
	    {
	    coffset=iline*pixmax+pixel+4; /* start at byte 5 for col.0, row 0 */
	    dn = x*(bimage1[coffset] - 127.5)
		 + y*(bimage2[coffset] - 127.5)
		 + z*(bimage3[coffset] - 127.5) + 128;
	    if (dn < 0) dn = 0;
	    if (dn > 255) dn = 255;
	    _setcolor(dn);
	    _setpixel(pixel,iline);
	    }
	 }
      _remappalette(0,pal0);
      _remappalette(7,pal7);
      }
}

void resetpal()
{
   /*  gray image display initialization  */
   pcolor = 0;
   _remapallpalette(&(pal[0]));
   pal0 = pal[0];
   pal7 = pal[7];
   for (glevel=0;glevel<11;glevel++)
      {
      goper[glevel]=0;
      }
}

void resetcpal()
{
   /*  color image display initialization  */
   pcolor = 1;
   _remapallpalette(&(cpal[0]));
   pal0 = cpal[0];
   pal7 = cpal[7];
   for (glevel=0;glevel<11;glevel++)
      {
      goper[glevel]=0;
      }
}

void phelp()
{
   char key=' ';

   _remappalette(0,0L);
   _remappalette(7,4144959L);
   _settextcolor(7);
   _settextwindow(1,1,25,40);

/*  write screen to image buffer 6  */
   _getimage(0,0,319,199,bimage6);
   ipcolor[6]=pcolor;
   qimage[6]=zpower;
   qlnorg[6]=lnorg;
   qpixorg[6]=pixorg;

/*  write help screens  */
   _clearscreen(_GWINDOW);
   _settextposition(1,1);

   _outtext("Load or Save Image to Screen/Buffer:\n");
   _outtext("    <D>  Display image from disk\n");
   _outtext("    <W>  Window image from disk\n");
   _outtext("    <1 - 6>  Display image buffer 1 - 6\n");
   _outtext("    <I>  Save screen to buffers 1 - 6\n\n");

   _outtext("    <O>  Change palette to pseudo-color\n\n");

   _outtext("Graphics Overlays:\n");
   _outtext("    <G>  Define graphic plane  [0 - 10]\n");
   _outtext("      COLORS:<R Y G C B M D W>,DN:0-255\n");
   _outtext("    <A>  Add a graphic plane to screen\n");
   _outtext("    <S>  Subtract a graphic plane\n");
   _outtext("    <R>  Restore image without graphics\n\n");
   _outtext("     - Press any key for next screen -");
   key = getch();
   _clearscreen(_GWINDOW);
   _settextposition(1,1);
   _outtext("Image Manipulation and Utilities:\n");
   _outtext("    <V>  Automatic Histogram Stretch\n");
   _outtext("    <M>  Gen. color image using buf 1-3\n");
   _outtext("    <L>  Gen. shade relief using buf 1-3");
   _outtext("    <C>  Enable cursor\n");
   _outtext("    <Z>  Zoom image by factor of two\n");
   _outtext("    <X>  Scatter Plot;y-axis buf1;x buf2");
   _outtext("    <P>  Plot spectra from BIL file\n");
   _outtext("    <Y>  Scale y-axis of spectra plot\n");
   _outtext("    <K>  Reset display palette to color\n");
   _outtext("    <B>  Reset display palette to b & w\n");
   _outtext("    <F>  Freq Histogram of all image buf");
   _outtext("    <f>  Freq Histogram of screen image\n");
   _outtext("    <E>  Temporary Exit to DOS\n\n");
   _outtext("   <ESC> QUIT program to DOS {TERMINATE}");
   _outtext("    <H>  Help\n\n");

/*  return image to screen from image buffer 6 and end */
   _outtext("     - Press any key to continue -");
   key = getch();
   _clearscreen(_GWINDOW);
   _putimage(0,0,bimage6,_GPSET);
   _remappalette(0,pal0);
   _remappalette(7,pal7);
}

void lnparse(int ip2)
{
/*  single line read to <cr>  */

   unsigned char inline[81];
   long iparsest, iparse, ipend, inptchar;
   int argcount;

   lnans[0]=0;
   lnans[1]=0;
   lnans[2]=0;
   lnans[3]=0;

   for (iparse=0; (iparse<80) && ((inptchar=getchar()) != EOF) && (inptchar != '\n');iparse++)
      {
      inline[iparse] = inptchar;
      }
   inline[iparse] = '\0';

   ipend=0;
   iparsest=0;
   argcount=0;
   while((argcount < ip2) && (iparsest < iparse))
      {
      if ((inline[iparsest] >= 48) && (inline[iparsest] <= 57))
	 {
	 lnans[argcount] = (lnans[argcount] * 10) + inline[iparsest++] - 48;
	 ipend=1;
	 }
      else
	 {
	 iparsest++;
	 if(ipend)
	    {
	    argcount++;
	    ipend=0;
	    }
	 }
      }
}

void clnparse()
{
/*  single line read to <cr>  (character string)  */

   int iparsest, iparse, inptchar;

   for(iparse=0; (iparse<80) && ((inptchar=getchar()) != EOF) && (inptchar != '\n'); iparse++)
      {
      clnans[iparse] = inptchar;
      }
   clnans[iparse] = '\0';
}


/* SUBROUTINE DISKIO */

void diskio(int op2,int *fd,unsigned char ibuf[8192],long fcb[129])

/* use global variables from main - iline, linemax, pixmax, message */
/* #include <fcntl.h> & <io.h> from main */
/* to use diskio as separate file, insert - #include "diskio.h"  */

{
   int reclen;
   long i,j,k,kst,kend,kinc,kmul;
   unsigned char filename[81];
   char key=' ';

   if ( op2 == 0 ) goto dopen;
   if ( op2 == 6 ) goto dclose;
   if ( op2 == 9 )
      goto dread;
   else
      goto dreturn;
dopen:
   /*  dup of open input file - DISKIO.FTN  */
   _outtext("Image Filename\n: ");
   /*  filename input by clnparse()  output name within clnans  */
   clnparse();
   if((*fd=open(clnans,O_RDONLY | O_BINARY))<0)
      {
      sprintf(message,"\"%s\": Can't Read\n\n      <press any key> to continue\n",clnans);
      _outtext(message);
      key=getch();
      fcb[1] = -2;
      goto dreturn;
      }
   reclen = read(*fd,ibuf,512);
   if( reclen <1 )
      {
      fprintf(stderr,"\"%s\": Can't Read Remapp Header\n",clnans);
      exit(1);
      }
   for(reclen=0;reclen<128;reclen++)
      {
      fcb[reclen+1]=ibuf[reclen*4]+ibuf[(reclen*4)+1]*256+ibuf[(reclen*4)+2]*65536+ibuf[(reclen*4)+3]*16777216;
      }
   /*  number of bytes (record len) = fcb[12]  */
   _outtext("\nEnter 1st Scanline, No.Scanlines,Skips: ");
   lnparse(3);
   fcb[5]=lnans[0];
   fcb[16]=lnans[1];
   fcb[7]=lnans[2];
   _outtext("\nEnter 1st Pixel,Number of Pixels,Skips: ");
   lnparse(3);
   fcb[4]=lnans[0];
   fcb[15]=lnans[1];
   fcb[6]=lnans[2];
   /*  default starting values  */
   if(fcb[5] <= 0)
      fcb[5]=1;
   if(fcb[4] <= 0)
      fcb[4]=1;
   /*  starting values too large?  */
   if(fcb[4] > fcb[23])
      fcb[4]=fcb[23];
   if(fcb[5] > fcb[24])
      fcb[5]=fcb[24];
   /*  nos. too large?  */
   if((fcb[4]+fcb[15]-1) > fcb[23])
      fcb[15]=fcb[23]-fcb[4]+1;
   if((fcb[5]+fcb[16]-1) > fcb[24])
      fcb[16]=fcb[24]-fcb[5]+1;
   /*  default window lengths  */
   if(fcb[15] <= 0)
      fcb[15]=fcb[23]-fcb[4]+1;
   if(fcb[16] <= 0)
      fcb[16]=fcb[24]-fcb[5]+1;
   /*  last record  */
   fcb[26]=fcb[5]+fcb[16]-1;
   if(fcb[26] > fcb[24])
      fcb[26]=fcb[24];
   fcb[26]=fcb[26]+1;
   /*  first record  */
   fcb[14]=fcb[5]+1;
   /*  last pixel  */
   fcb[27]=fcb[4]+fcb[15]-1;
   if(fcb[27] > fcb[23])
      fcb[27]=fcb[23];
   /*  acual no. pixels and scanlines  */
   fcb[2]=(fcb[15]-1)/(fcb[6]+1)+1;
   if(fcb[2]<pixmax)
      pixmax=fcb[2];
   fcb[3]=(fcb[16]-1)/(fcb[7]+1)+1;
   if(fcb[3]<linemax)
      linemax=fcb[3];
   fcb[21]=0;
   /*  end of DISKIO open input  */
   goto dreturn;

dread:
   /*  DISKIO.FTN  Read a record  */
   fcb[1]=0;
   if(fcb[14] < fcb[5]+1)
      {
      printf("DISKIO:ERROR ON FILE \n");
      exit(1);
      }
   lseek(*fd,fcb[12]*(fcb[14]-1),SEEK_SET);
   reclen = read(*fd,ibuf,fcb[12]);
   if(reclen<0)
      {
      fprintf(stderr,"Error Reading File.\n");
      exit(1);
      }
   if(reclen==0)
      {
      iline=linemax;
      }
   if(iline != linemax)
      {
      fcb[14]=fcb[14]+1+fcb[7];
      /*  extract a subset of line if desired  */
      if((fcb[4] != 1) || (fcb[6] != 0))
	 {
	 i=0;
	 kmul=fcb[25]/8;
	 kst=(fcb[4]-1)*kmul;
	 kend=(fcb[27]-1)*kmul;
	 kinc=(fcb[6]+1)*kmul;
	 for(k=kst; k<kend+1; k+=kinc)
	    {
	    for(j=k; j<k+kmul; j++)
	       {
	       ibuf[i]=ibuf[j];
	       i++;
	       }
	    }
	 }
      }
   /*  end DISKIO.FOR  READ  */
   goto dreturn;

dclose:
   close(*fd);

dreturn:
;
}

