/* imginout.c input/output routines for stscan.c */
#include <exec/exec.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <graphics/rastport.h>
#include <libraries/reqbase.h>
#include <req_pragmas.h>
#include <stdio.h>
#include <string.h>
#include <functions.h>
#include "stscan.h"

#define ST400LUN 96
#define DEV_NAME (char*)"scsi.device" /* <- change for other SCSI controller */
#define FORM 0x464f524d
#define ILBM 0x494c424d
#define BMHD 0x424d4844
#define BODY 0x424f4459
#define DIR_READ  1
#define DIR_WRITE 0

/* Scanner specific sizes and commands */

static UWORD cornerxval[]={  22,  33,  44, 266, 399, 535};
static UWORD corneryval[]={   6,   6,   6,   6,   6,   6};
static UWORD widthval[]=  {1664,2496,3312,1168,1760,2336};
static UWORD heightval[]= {2336,3504,4672,1656,2484,3312};

static UBYTE cmd_scan[]={0x1b,ST400LUN,0,0,0,0};
static UBYTE cmd_read[]={0x28,ST400LUN,0,0,0,0,0,0,0,0};
static UBYTE cmd_dwin[]={0x24,ST400LUN,0,0,0,0,0,0,40,0};
static UBYTE cmd_mdon[]={0x15,ST400LUN,0,0,0,128};
static UBYTE cmd_mdoff[]={0x15,ST400LUN,0,0,0,0};
static UBYTE cmd_inqu[]={0x12,ST400LUN,0,0,96,0};

/* IFF-ILBM Constants */

static UBYTE iff_cmap_bw[]=
{'C','M','A','P',0,0,0,6,0,0,0,255,255,255};

static UBYTE iff_cmap_gray[]=
{'C','M','A','P',0,0,0,48,0,0,0,16,16,16,32,32,32,48,48,48,64,64,64,80,80,80,
 96,96,96,112,112,112,128,128,128,144,144,144,160,160,160,176,176,176,
 192,192,192,208,208,208,224,224,224,240,240,240};

static ULONG iff_head[]={FORM,0,ILBM,BMHD,20,0,0,0,0x00000101,0x02800200};

static ULONG iff_body[]={BODY,0};

static ULONG chunk_hd[2];

typedef struct iffhead
{ ULONG iff_magic;
  ULONG filelen;
  ULONG ilbm_magic;
  ULONG bmhd_magic;
  ULONG bmhd_len;
  UWORD w,h,x,y;
  UBYTE d, mask, cmp, pad;
  UWORD transparent,aspect,pw,ph;
};

static struct iffhead iffheader;

UBYTE sk;
UWORD vx,vy;

/* Call of the File Requester */

struct IntuiText text_na;
struct IntuiText text_aha;

static char def_name[REQ_FCHARS]="";
static char def_dir[REQ_DSIZE]="";
static char str_filenam[REQ_FCHARS+REQ_DSIZE]="";

USHORT filerequest(char *titel,char *str_filenam)
{ struct Process *OurTask;
  struct Window	*old_pr_WindowPtr;
  struct FileReq freq;

  OurTask = (struct Process *)FindTask((char *)0L);
  old_pr_WindowPtr = OurTask->pr_WindowPtr;
  OurTask->pr_WindowPtr = win;
  
  memset(&freq,0,sizeof(freq));
  str_filenam[0]=0;
  freq.Title=titel;
  freq.PathName=str_filenam;
  freq.Dir=def_dir;
  freq.File=def_name;
  if (FileRequester(&freq))
  { OurTask->pr_WindowPtr = old_pr_WindowPtr;
    return(1);
  }
  else
  {
    OurTask->pr_WindowPtr = old_pr_WindowPtr;
    return(0);
  }
} 

void MessReq(UBYTE *string)
{ struct Process *OurTask;
  struct Window	*old_pr_WindowPtr;
  struct TRStructure tr;

  OurTask = (struct Process *)FindTask((char *)0L);
  old_pr_WindowPtr = OurTask->pr_WindowPtr;
  OurTask->pr_WindowPtr = win;
  memset(&tr,0,sizeof(tr));
  tr.Text=string;
  tr.Title="Program Message";
  TextRequest(&tr);
  OurTask->pr_WindowPtr = old_pr_WindowPtr;
}

void NotAvailable()
{  MessReq((UBYTE *)"Funktion not available!");
}

UBYTE DoScsi(UBYTE *cmd, UWORD cmdlen, UWORD *data, ULONG datalen, UBYTE flags)
{ struct SCSICmd scmd;
  scmd.scsi_Command=cmd;
  scmd.scsi_CmdLength=cmdlen;
  scmd.scsi_Data=data;
  scmd.scsi_Length=datalen;
  scmd.scsi_Flags=flags;
  diskreq->io_Length = sizeof(struct SCSICmd);
  diskreq->io_Data = &scmd;
  diskreq->io_Command = 28;
  DoIO(diskreq);
  return(scmd.scsi_Status);
}


void inquiry()
{ UBYTE string[96],inq_txt[45];

  DoScsi(&cmd_inqu,6,(UWORD *)&string,96,DIR_READ);
  strncpy(&inq_txt[0],&string[8],39);
  MessReq(&inq_txt[0]);
}

void scan()
{ ULONG memsize,memadd,blsize;
  short tabindex,blocks,rest,i,glin,rlin;
  UBYTE *rdptr;

  if (memptr) free(memptr);
  memneed=0;
  tabindex=((winpar.resx/100)-2)+(winpar.size-4)*3;
  winpar.cornerx=cornerxval[tabindex];
  winpar.cornery=corneryval[tabindex];
  winpar.width=widthval[tabindex];
  winpar.height=heightval[tabindex];
  memsize=(winpar.halftone)?((ULONG)winpar.width*(ULONG)winpar.height)>>1:
                            ((ULONG)winpar.width*(ULONG)winpar.height)>>3;
  memadd=(memgray)?((ULONG)memwidth*ADDLIN)>>1:
                   ((ULONG)memwidth*ADDLIN)>>3;
  if ((memptr=(UBYTE*)malloc(memsize+memadd))==NULL)
    MessReq((UBYTE*)"Out of Memmory!");
  else 
  { memneed=memsize;
    memwidth=winpar.width;
    memheight=winpar.height;
    memgray=winpar.halftone;
    rdptr=memptr;
    if (!(winpar.halftone))
    { DoScsi(&cmd_mdon,6,NULL,0,0);
      Delay(100);
      DoScsi(&cmd_dwin,10,&winpar,40,DIR_WRITE);
      DoScsi(&cmd_scan,6,NULL,0,0);
      blocks=memsize/0x8000;
      rest=memsize%0x8000;
      cmd_read[7]=128; cmd_read[8]=0;
      for (i=0;i<blocks;i++) 
      { DoScsi(&cmd_read,10,rdptr,0x8000,DIR_READ);
        rdptr+=0x8000;
      }
      cmd_read[7]=(rest>>8)&0xff; cmd_read[8]=rest&0xff;
      DoScsi(&cmd_read,10,rdptr,rest,DIR_READ);
      rdptr+=rest;
    }
    else
    { glin=winpar.height;
      rlin=0x200000L/(ULONG)winpar.width; 
      do 
      { if (rlin>glin) rlin=glin;
        winpar.height=rlin;
        glin-=rlin;
        DoScsi(&cmd_mdon,6,NULL,0,0);
        Delay(100);
        DoScsi(&cmd_dwin,10,&winpar,40,DIR_WRITE);
        DoScsi(&cmd_scan,6,NULL,0,0);
	winpar.cornery+=rlin;
        blsize=((ULONG)winpar.height*(ULONG)winpar.width)>>1;
        blocks=blsize/0x4000;
        rest=blsize%0x4000;
        cmd_read[7]=128; cmd_read[8]=0;
        for (i=0;i<blocks;i++) 
        { DoScsi(&cmd_read,10,rdptr,0x8000,DIR_READ);
          p64to16(rdptr,0x4000);
          rdptr+=0x4000;
        }
        cmd_read[7]=(rest>>7)&0xff; cmd_read[8]=(rest<<1)&0xff;
        DoScsi(&cmd_read,10,rdptr,rest<<1,DIR_READ);
        p64to16(rdptr,rest);
	rdptr+=rest;
      } while (glin);
    }
    DoScsi(&cmd_mdoff,6,NULL,0,0); 
  }
}  
    

static ULONG cmpline(UBYTE *zeile, UWORD len, UWORD pnum, FILE *qdatei)
{ ULONG count;
  UWORD plen,p;
  UBYTE m;
  WORD i,j;
  static UBYTE cplane[6000];

  count=0;
  plen=len/pnum;
  for (p=0;p<pnum;p++)
  { i=0;
    while(i<plen)
    { m=(*(zeile+i));
      for (j=i+1;((m==(*(zeile+j)))&&(j<plen)&&(j<(i+125)));j++);
      if (j!=(i+1))
      { cplane[count++]=(UBYTE)((257-j+i)&0xff);
        cplane[count++]=m;
        i=j;
      }
      else
      { for (;(m!=(*(zeile+j))&&(j<=plen)&&(j<(i+125)));m=(*(zeile+(j++))));
        if (j<plen) j-=2;
        j=((plen-1)<j)?(plen-1):j;
        cplane[count++]=(UBYTE)(j-i);
        for(;i<=j;cplane[count++]=(*(zeile+(i++))));
      }
    }
    zeile+=plen;
  }
  fwrite(&cplane[0],count,1,qdatei);
  return(count);
}


void load()
{ FILE *sdatei;
  ULONG memsize,memadd;
  UWORD i,j,t;
  UBYTE *loadptr;
  UBYTE planes[4000];
  UBYTE b,cflag,rflag,cnt,cval;
  UWORD bflag=1;

  if (filerequest("Load IFF File",str_filenam))
  { sdatei=fopen(str_filenam,"rb");
    fread(&iffheader,sizeof(iffheader),1,sdatei);
    if ((iffheader.iff_magic!=FORM)||(iffheader.ilbm_magic!=ILBM)||
        (iffheader.bmhd_magic!=BMHD)||(iffheader.bmhd_len!=20))
    { MessReq("No IFF-ILBM File!");
      fclose(sdatei);
    }
    else
    { if (memptr) free(memptr);
      memneed=0;
      memgray=((iffheader.d)!=1);
      memwidth=iffheader.w;
      memheight=iffheader.h;
      memsize=(memgray)?((ULONG)memwidth*(ULONG)memheight)>>1:
                        ((ULONG)memwidth*(ULONG)memheight)>>3;
      memadd=(memgray)?((ULONG)memwidth*ADDLIN)>>1:
                       ((ULONG)memwidth*ADDLIN)>>3;
      if ((memptr=(UBYTE*)malloc(memsize+memadd))==NULL)
      { MessReq((UBYTE*)"Out of Memmory!");
        fclose(sdatei);
      }
      else
      { memneed=memsize;
        while (bflag) /* hier CMAP und Body suchen */
        { fread(&chunk_hd[0],8,1,sdatei);
          if (chunk_hd[0]==BODY) bflag=0;
          else fseek(sdatei,chunk_hd[1],SEEK_CUR);
        }
        if (memgray)
        { loadptr=memptr;
          memset(&planes[0],0,4000);
          if (iffheader.cmp) for (i=0;i<memheight;i++)
          { t=0;
            while (t<iffheader.d*(memwidth<<3))
            { fread(&cnt,1,1,sdatei);
              if (cnt>128)
              { fread(&cval,1,1,sdatei);
                for (i=0;i<(257-cnt);i++) planes[t++]=cval;
              }
              if (cnt<128)
              { fread(&planes[t],++cnt,1,sdatei);
                t+=cnt;
              }
            }
            fplanegen(loadptr,&planes[0],&planes[memwidth>>3],
                      &planes[2*(memwidth>>3)],&planes[3*(memwidth>>3)],(memwidth>>3));
            loadptr+=(memwidth>>1);
          }
          else for (i=0;i<memheight;i++)
          { fread(&planes[0],iffheader.d*(memwidth>>3),1,sdatei);
            fplanegen(loadptr,&planes[0],&planes[memwidth>>3],
                      &planes[2*(memwidth>>3)],&planes[3*(memwidth>>3)],(memwidth>>3));
            loadptr+=(memwidth>>1);
          }
        }
        else
        { if (iffheader.cmp)
          { loadptr=memptr;
            while ((fread(&cnt,1,1,sdatei)))
            { if (cnt>128)
              { fread(&cval,1,1,sdatei);
                for (i=0;i<(257-cnt);i++) *(loadptr++)=cval;
              }
              if (cnt<128)
              { fread(loadptr,++cnt,1,sdatei);
                loadptr+=cnt;
              }
            }
          }
          else fread(memptr,(iffheader.w>>3)*iffheader.h,1,sdatei);
        }
        fclose(sdatei);
      }
    }
  }
}

void save(UWORD wx1,UWORD wy1,UWORD wx2,UWORD wy2,UBYTE cmp,UBYTE mf)
{ FILE *qdatei;
  ULONG totlen,bmlen;
  UWORD width,height,i,t;
  ULONG startofs,cmplen;
  UBYTE *saveptr;
  UBYTE planes[4000];
  UBYTE sf;
  UBYTE dummy=0;

  if (filerequest("Save IFF File",str_filenam))
  { sf=(memgray)?1:3;
    if (mf==2)
    { if (wx1>wx2) {t=wx2; wx2=wx1; wx1=t;}
      if (wy1>wy2) {t=wy2; wy2=wy1; wy1=t;}
      width=(wx2-wx1);
      height=(wy2-wy1);
      startofs=wy1*(memwidth>>sf)+(wx1>>sf);
    }
    else 
    { width=memwidth;
      height=memheight;
      startofs=0;
    }
    width&=0xfff0;
    qdatei=fopen(str_filenam,"wb");
    bmlen=(memgray)?((width>>1)*height):((width>>3)*height);
    totlen=bmlen+40+((memgray)?56:14);
    iff_head[1]=totlen; 
    iff_head[5]=(width<<16)|height;
    iff_head[7]=((memgray)?0x04000000:0x01000000)|((cmp)?0x0100:0);
    iff_body[1]=bmlen;
    fwrite(&iff_head[0],sizeof(iff_head),1,qdatei);
    if (memgray) fwrite(iff_cmap_gray,sizeof(iff_cmap_gray),1,qdatei);
    else fwrite(iff_cmap_bw,sizeof(iff_cmap_bw),1,qdatei);
    fwrite(iff_body,sizeof(iff_body),1,qdatei);
    saveptr=memptr+startofs;
    cmplen=0;
    if (memgray) for (i=0;i<height;i++)
    { fplanesep(saveptr,&planes[0],&planes[width>>3],&planes[2*(width>>3)],&planes[3*(width>>3)],(width>>3));
      if (cmp) cmplen+=cmpline(&planes[0],width>>1,4,qdatei);
      else fwrite(&planes[0],width>>1,1,qdatei);
      saveptr+=(ULONG)(memwidth>>1);
    }
    else for (i=0;i<height;i++)
    { if (cmp) cmplen+=cmpline(saveptr,width>>3,1,qdatei);
      else fwrite(saveptr,width>>3,1,qdatei);
      saveptr+=(ULONG)(memwidth>>3);
    }
    if (cmp)
    { if (cmplen&1) fwrite(&dummy,1,1,qdatei);
      fseek(qdatei,sizeof(iff_head)+((memgray)?(sizeof(iff_cmap_gray)):
            (sizeof(iff_cmap_bw)))+4,SEEK_SET);
      fwrite(&cmplen,4,1,qdatei);
      if (cmplen&1) cmplen++;
      fseek(qdatei,4,SEEK_SET);
      cmplen+=((memgray)?96:54);
      fwrite(&cmplen,4,1,qdatei);
    }
    fclose(qdatei); 
  }
}

void view(UWORD x, UWORD y, UBYTE zoom)
{ UBYTE *vptr;
  UBYTE *plptr[4];
  ULONG vinc;
  ULONG vicr[13];
  UWORD i,j,k,n1,n2,zeile;
  UBYTE linebuf[1000];

  for (i=0;i<4;i++) plptr[i]=(UBYTE *)(rp->BitMap->Planes[i]+1680);
  vptr=(memgray)?
       (UBYTE*)(memptr+(((memwidth>>1)*y)+(x>>1))):
       (UBYTE*)(memptr+(((memwidth>>3)*y)+(x>>3)));
  vinc=(memgray)?(ULONG)(memwidth>>1):(ULONG)(memwidth>>3);
  if (zoom)
  { if ((memheight/4)<VIEWHEIGHT) sk=4;
    else if ((memheight/8)<VIEWHEIGHT) sk=8;
    else if ((memheight/12)<VIEWHEIGHT) sk=12;
    vptr=memptr;
    vicr[0]=0; vicr[1]=vinc;
    for (i=2;i<13;i++) vicr[i]=vicr[i-1]+vinc;
    clrscr(plptr[0],plptr[1],plptr[2],plptr[3]);
    zeile=0; vx=vy=0;
    if (memgray)
    switch (sk)
    { case 4: while(zeile<memheight)
              { zeile+=4;
                for (i=0;i<(memwidth>>1);i+=4)
                { n1=n2=0; j=i;
                  for (k=0;k<4;k++)
                  { n1+=((*(vptr+j  )>>4)+(*(vptr+j  )&15)+(*(vptr+j+1)>>4)+(*(vptr+j+1)&15));
                    n2+=((*(vptr+j+2)>>4)+(*(vptr+j+2)&15)+(*(vptr+j+3)>>4)+(*(vptr+j+3)&15));
                    j+=vinc;
                  }
                  linebuf[i>>2]=(n1&0xf0)|(n2>>4);
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>5);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[4];
              } 
              break;
      case 8: while(zeile<memheight)
              { zeile+=8;
                for (i=0;i<(memwidth>>1);i+=8)
                { n1=n2=0; j=i;
                  for (k=0;k<8;k++)
                  { n1+=((*(vptr+j  )>>4)+(*(vptr+j  )&15)+(*(vptr+j+1)>>4)+(*(vptr+j+1)&15)
                        +(*(vptr+j+2)>>4)+(*(vptr+j+2)&15)+(*(vptr+j+3)>>4)+(*(vptr+j+3)&15));
                    n2+=((*(vptr+j+4)>>4)+(*(vptr+j+4)&15)+(*(vptr+j+5)>>4)+(*(vptr+j+5)&15)
                        +(*(vptr+j+6)>>4)+(*(vptr+j+6)&15)+(*(vptr+j+7)>>4)+(*(vptr+j+7)&15));
                    j+=vinc;
                  }
                  linebuf[i>>3]=((n1>>2)&0xf0)|((n2>>6)&0x0f);
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>6);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[8];
              } 
              break;
      case 12:while(zeile<memheight)
              { zeile+=12;
                for (i=0;i<(memwidth>>1);i+=12)
                { n1=n2=0; j=i;
                  for (k=0;k<12;k++)
                  { n1+=((*(vptr+j   )>>4)+(*(vptr+j   )&15)+(*(vptr+j+ 1)>>4)+(*(vptr+j+ 1)&15)
                        +(*(vptr+j+ 2)>>4)+(*(vptr+j+ 2)&15)+(*(vptr+j+ 3)>>4)+(*(vptr+j+ 3)&15)
                        +(*(vptr+j+ 4)>>4)+(*(vptr+j+ 4)&15)+(*(vptr+j+ 5)>>4)+(*(vptr+j+ 5)&15));
                    n2+=((*(vptr+j+ 6)>>4)+(*(vptr+j+ 6)&15)+(*(vptr+j+ 7)>>4)+(*(vptr+j+ 7)&15)
                        +(*(vptr+j+ 8)>>4)+(*(vptr+j+ 8)&15)+(*(vptr+j+ 9)>>4)+(*(vptr+j+ 9)&15)
                        +(*(vptr+j+10)>>4)+(*(vptr+j+10)&15)+(*(vptr+j+11)>>4)+(*(vptr+j+11)&15));
                    j+=vinc;
                  }
                  linebuf[i/12]=(((n1/144)<<4)&0xf0)|((n2/144)&0x0f);
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth/96);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[12];
              } 
              break;
    }
    else
    switch (sk)
    { case 4: while(zeile<memheight)
              { zeile+=4;
                for (i=0;i<(memwidth>>3);i++)
                { n1=numbits[(*(vptr+i        ))>>4]+numbits[(*(vptr+i+vicr[1]))>>4]
                    +numbits[(*(vptr+i+vicr[2]))>>4]+numbits[(*(vptr+i+vicr[3]))>>4];
                  if (n1==16) n1=15;
                  n2=numbits[(*(vptr+i        ))&15]+numbits[(*(vptr+i+vicr[1]))&15]
                    +numbits[(*(vptr+i+vicr[2]))&15]+numbits[(*(vptr+i+vicr[3]))&15];
                  if (n2==16) n2=15;
                  linebuf[i]=(~((n1<<4)|n2));
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>5);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[4];
              } 
              break;
      case 8: while(zeile<memheight)
              { zeile+=8;
                for (i=0;i<(memwidth>>3);i+=2)
                { n1=(numbits[(*(vptr+i        ))]
                     +numbits[(*(vptr+i+vicr[1]))]
                     +numbits[(*(vptr+i+vicr[2]))]
                     +numbits[(*(vptr+i+vicr[3]))]
                     +numbits[(*(vptr+i+vicr[4]))]
                     +numbits[(*(vptr+i+vicr[5]))]
                     +numbits[(*(vptr+i+vicr[6]))]
                     +numbits[(*(vptr+i+vicr[7]))])>>2;
                  if (n1==16) n1=15;
                  n2=(numbits[(*(vptr+i+1        ))]
                     +numbits[(*(vptr+i+1+vicr[1]))]
                     +numbits[(*(vptr+i+1+vicr[2]))]
                     +numbits[(*(vptr+i+1+vicr[3]))]
                     +numbits[(*(vptr+i+1+vicr[4]))]
                     +numbits[(*(vptr+i+1+vicr[5]))]
                     +numbits[(*(vptr+i+1+vicr[6]))]
                     +numbits[(*(vptr+i+1+vicr[7]))])>>2;
                  if (n2==16) n2=15;
                  linebuf[i>>1]=(~((n1<<4)|n2));
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>6);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[8];
              } 
              break;
      case 12:while(zeile<memheight)
              { zeile+=12;
                for (i=0;i<(memwidth>>3);i+=3)
                { n1=(numbits[(*(vptr+i           ))]
                     +numbits[(*(vptr+i+  vicr[ 1]))]
                     +numbits[(*(vptr+i+  vicr[ 2]))]
                     +numbits[(*(vptr+i+  vicr[ 3]))]
                     +numbits[(*(vptr+i+  vicr[ 4]))]
                     +numbits[(*(vptr+i+  vicr[ 5]))]
                     +numbits[(*(vptr+i+  vicr[ 6]))]
                     +numbits[(*(vptr+i+  vicr[ 7]))]
                     +numbits[(*(vptr+i+  vicr[ 8]))]
                     +numbits[(*(vptr+i+  vicr[ 9]))]
                     +numbits[(*(vptr+i+  vicr[10]))]
                     +numbits[(*(vptr+i+  vicr[11]))]
                     +numbits[(*(vptr+i+1         ))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 1]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 2]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 3]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 4]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 5]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 6]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 7]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 8]))>>4]
                     +numbits[(*(vptr+i+1+vicr[ 9]))>>4]
                     +numbits[(*(vptr+i+1+vicr[10]))>>4]
                     +numbits[(*(vptr+i+1+vicr[11]))>>4]);
                  n2=(numbits[(*(vptr+i+2         ))]
                     +numbits[(*(vptr+i+2+vicr[ 1]))]
                     +numbits[(*(vptr+i+2+vicr[ 2]))]
                     +numbits[(*(vptr+i+2+vicr[ 3]))]
                     +numbits[(*(vptr+i+2+vicr[ 4]))]
                     +numbits[(*(vptr+i+2+vicr[ 5]))]
                     +numbits[(*(vptr+i+2+vicr[ 6]))]
                     +numbits[(*(vptr+i+2+vicr[ 7]))]
                     +numbits[(*(vptr+i+2+vicr[ 8]))]
                     +numbits[(*(vptr+i+2+vicr[ 9]))]
                     +numbits[(*(vptr+i+2+vicr[10]))]
                     +numbits[(*(vptr+i+2+vicr[11]))]
                     +numbits[(*(vptr+i+1         ))&15]
                     +numbits[(*(vptr+i+1+vicr[ 1]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 2]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 3]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 4]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 5]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 6]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 7]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 8]))&15]
                     +numbits[(*(vptr+i+1+vicr[ 9]))&15]
                     +numbits[(*(vptr+i+1+vicr[10]))&15]
                     +numbits[(*(vptr+i+1+vicr[11]))&15]);
                  n1=n1/9;
                  n2=n2/9;
                  if (n1==16) n1=15;
                  if (n2==16) n2=15;
                  linebuf[i/3]=(~((n1<<4)|n2));
                }
                vplanesep(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth/96);
                plptr[0]+=80; plptr[1]+=80; plptr[2]+=80; plptr[3]+=80;
                vptr+=vicr[12];
              } 
              break;
    }    
  }
  else
  { vx=x&0xfff0; vy=y&0xfffe; sk=1;
    if (memgray) grayview(vptr,plptr[0],plptr[1],plptr[2],plptr[3],vinc); 
    else bwview(vptr,plptr[0],plptr[1],plptr[2],plptr[3],vinc); 
  } 
}

UWORD s2px(UWORD x)
{ int t;
  t=x*sk+vx;
  if (t>=memwidth) t=memwidth-1;
  if (t<0) t=0;
  return((UWORD)t);
}

UWORD s2py(UWORD y)
{ int t;
  t=y*sk+vy;
  if (t>=memheight) t=memheight-1;
  if (t<0) t=0;
  return((UWORD)t);
}

UWORD p2sx(UWORD x)
{ int t;
  t=(x-vx)/sk;
  if (t>623) t=623;
  if (t<0) t=0;
  return((UWORD)t);
}

UWORD p2sy(UWORD y)
{ int t;
  t=(y-vy)/sk;
  if (t>(VIEWHEIGHT-1)) t=VIEWHEIGHT-1;
  if (t<0) t=0;
  return((UWORD)t);
}

void drawbox(UWORD wx1,UWORD wy1,UWORD wx2,UWORD wy2,struct RastPort *wrp)
{ UWORD sx1,sy1,sx2,sy2;
  
  sx1=p2sx(wx1); sy1=p2sy(wy1)+11;
  sx2=p2sx(wx2); sy2=p2sy(wy2)+11; 
  SetWrMsk(wrp,8);
  SetAPen(wrp,8);
  SetDrMd(wrp,COMPLEMENT|JAM1);
  SetDrPt(wrp,0xcccc);
  Move(wrp,sx1,sy1);
  Draw(wrp,sx1,sy2);
  Draw(wrp,sx2,sy2);
  Draw(wrp,sx2,sy1);
  Draw(wrp,sx1,sy1);
  SetWrMsk(wrp,1);
  SetAPen(wrp,1);
  SetDrMd(wrp,COMPLEMENT|JAM1);
  SetDrPt(wrp,0x3333);
  Move(wrp,sx1,sy1);
  Draw(wrp,sx1,sy2);
  Draw(wrp,sx2,sy2);
  Draw(wrp,sx2,sy1);
  Draw(wrp,sx1,sy1);
  SetWrMsk(wrp,15);
}

void cut(UWORD wx1,UWORD wy1,UWORD wx2,UWORD wy2,UBYTE mf)
{ UWORD width,height,x,y,t;
  ULONG startofs;
  UBYTE *picptr,*cpyptr;
  UBYTE sf;

  sf=(memgray)?1:3;
  if ((memwidth<=640)||(memheight<=512)) MessReq("Area already has minimal size");
  if (mf!=2) MessReq("No Area selected!");
  else
  { if (wx1>wx2) {t=wx2; wx2=wx1; wx1=t;}
    if (wy1>wy2) {t=wy2; wy2=wy1; wy1=t;}
    width=(wx2-wx1);
    height=(wy2-wy1);
    if (height<512) 
    { height=512;
      if ((wy1+height)>memheight) wy1=memheight-height;
    }
    if (width<640) 
    { width=640;
      if ((wx1+width)>memwidth) wx1=memwidth-width;
    }
    startofs=wy1*(memwidth>>sf)+(wx1>>sf);
    picptr=memptr;
    for (y=0;y<height;y++)
    { cpyptr=memptr+startofs;
      for(x=0;x<(width>>sf);x++) *(picptr++)=*(cpyptr++);
      startofs+=(ULONG)(memwidth>>sf);
    }
    mf=0;
    memwidth=width;
    memheight=height;
    if (!(memptr=(UBYTE *)realloc(memptr,(memwidth*(memheight+ADDLIN))>>sf)))
    { memneed=0;
      MessReq((UBYTE *)"Out Of Memory!");
    }
  }
}
