/*
**      $VER: imginout.c 3.00D (11.8.97)
**
**      STScan input/output routines
**
**      Written by Frank-Christian Kruegel, Henning Peters, Andreas R. Kleinert
**      GNU General Public License V2
*/

#include "stscan.h"

#define ST400LUN 96
#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, 432, 652, 868};
static UWORD corneryval[]={   6,   6,   6,   6,   6,   6,   6,   6,   6};
static UWORD widthval[]=  {1664,2496,3312,1168,1760,2336, 816,1248,1648};
static UWORD heightval[]= {2336,3504,4672,1656,2484,3312,1168,1760,2336};

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 UBYTE iff_cmap_ext[]=
{'C','M','A','P',0,0,3,0,
 0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x03,
 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x06,0x06,0x07,0x07,0x07,
 0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,0x0a,0x0b,0x0b,0x0b,
 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,
 0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,
 0x14,0x14,0x14,0x15,0x15,0x15,0x16,0x16,0x16,0x17,0x17,0x17,
 0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,0x1b,0x1b,
 0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1f,0x1f,0x1f,
 0x20,0x20,0x20,0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,
 0x24,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x26,0x27,0x27,0x27,
 0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,
 0x2c,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,
 0x30,0x30,0x30,0x31,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33,
 0x34,0x34,0x34,0x35,0x35,0x35,0x36,0x36,0x36,0x37,0x37,0x37,
 0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,
 0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,
 0x40,0x40,0x40,0x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43,0x43,
 0x44,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47,
 0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,
 0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,
 0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x53,
 0x54,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,
 0x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5b,
 0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,0x5e,0x5e,0x5f,0x5f,0x5f,
 0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x63,
 0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,
 0x68,0x68,0x68,0x69,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6b,
 0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x6f,
 0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x73,
 0x74,0x74,0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,
 0x78,0x78,0x78,0x79,0x79,0x79,0x7a,0x7a,0x7a,0x7b,0x7b,0x7b,
 0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,
 0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x82,0x83,0x83,0x83,
 0x84,0x84,0x84,0x85,0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,
 0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,
 0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,
 0x90,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x92,0x93,0x93,0x93,
 0x94,0x94,0x94,0x95,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x97,
 0x98,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b,0x9b,
 0x9c,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0x9f,
 0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,
 0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa7,
 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xaa,0xab,0xab,0xab,
 0xac,0xac,0xac,0xad,0xad,0xad,0xae,0xae,0xae,0xaf,0xaf,0xaf,
 0xb0,0xb0,0xb0,0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3,0xb3,0xb3,
 0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6,0xb6,0xb6,0xb7,0xb7,0xb7,
 0xb8,0xb8,0xb8,0xb9,0xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,0xbb,
 0xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,
 0xc0,0xc0,0xc0,0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,
 0xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,
 0xc8,0xc8,0xc8,0xc9,0xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,0xcb,
 0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce,0xce,0xce,0xcf,0xcf,0xcf,
 0xd0,0xd0,0xd0,0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,
 0xd4,0xd4,0xd4,0xd5,0xd5,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,
 0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xda,0xda,0xda,0xdb,0xdb,0xdb,
 0xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xde,0xde,0xde,0xdf,0xdf,0xdf,
 0xe0,0xe0,0xe0,0xe1,0xe1,0xe1,0xe2,0xe2,0xe2,0xe3,0xe3,0xe3,
 0xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe7,
 0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,
 0xec,0xec,0xec,0xed,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xef,
 0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf2,0xf3,0xf3,0xf3,
 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf7,
 0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,
 0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xff
};

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;
} iffhead;

static struct iffhead iffheader;

UBYTE sk;
UWORD vx,vy;
static char str_filenam[256] = "";

USHORT filerequest(char *titel,char *str_filenam)
{
        struct rtFileRequester *filereq;
        char filename[34];

        if ((filereq=rtAllocRequestA(RT_FILEREQ, NULL))) {
                if (rtFileRequest(filereq, filename, titel, TAG_END)) {
                        strcpy(str_filenam,filereq->Dir);
                        strcat(str_filenam,filename);
                        return 1;
                }
        }
        return 0;
}

void MessReq(UBYTE *string) {
  rtEZRequest(string, "Ok", NULL, NULL);
}

void NotAvailable(void)
{  MessReq((UBYTE *)"Funktion nicht da!");
}

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(void)
{ UBYTE string[96],inq_txt[45];

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

void scan(void)
{ 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/*+32768*/))==NULL)
                MessReq((UBYTE*)"Kein Speicher!");
        else
        { memneed=memsize;
                memwidth=winpar.width;
                memheight=winpar.height;
                memgray=winpar.halftone;
                rdptr=memptr;
                if (!(winpar.halftone))
                { DoScsi(&cmd_mdon[0],6,(UWORD *)NULL,0,0);
                        Delay(100);
                        DoScsi(&cmd_dwin[0],10,(UWORD *)&winpar,40,DIR_WRITE);
                        DoScsi(&cmd_scan[0],6,(UWORD *)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[0],10,(UWORD *)rdptr,0x8000,DIR_READ); */
                                DoScsi(&cmd_read[0],10,(UWORD *)bufptr,0x8000,DIR_READ);
        memcpy(rdptr,bufptr,0x8000);
                                rdptr+=0x8000;
                        }
                        cmd_read[7]=(rest>>8)&0xff; cmd_read[8]=rest&0xff;
                        /* DoScsi(&cmd_read[0],10,(UWORD *)rdptr,rest,DIR_READ); */
                        DoScsi(&cmd_read[0],10,(UWORD *)bufptr,rest,DIR_READ);
                        memcpy(rdptr,bufptr,rest);
                        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[0],6,(UWORD *)NULL,0,0);
                                Delay(100);
                                DoScsi(&cmd_dwin[0],10,(UWORD *)&winpar,40,DIR_WRITE);
                                DoScsi(&cmd_scan[0],6,(UWORD *)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[0],10,(UWORD *)bufptr,0x8000,DIR_READ);
                                        p64to16(bufptr,rdptr,0x4000);
                                        rdptr+=0x4000;
                                }
                                cmd_read[7]=(rest>>7)&0xff; cmd_read[8]=(rest<<1)&0xff;
                                DoScsi(&cmd_read[0],10,(UWORD *)bufptr,rest<<1,DIR_READ);
                                p64to16(bufptr,rdptr,rest);
        rdptr+=rest;
                        } while (glin);
                }
                DoScsi(&cmd_mdoff[0],6,(UWORD *)NULL,0,0);
        }
        if (!(memptr=(UBYTE *)realloc(memptr,memsize+memadd)))
        { memneed=0;
                MessReq((UBYTE *)"Kein Speicher");
        }

}

void diskscan(void)
{ FILE *qdatei;
        ULONG totlen,bmlen;
        UWORD width,height,i,j,k;
        UBYTE msk;
        UBYTE planes[8][500];
        struct DefWindow dskwinpar;
        short tabindex,glin,rlin;

        if (filerequest("Speichere IFF File",str_filenam))
        { width=memwidth;
                height=memheight;
        }
        width&=0xfff0;
        qdatei=fopen(str_filenam,"wb");
        bmlen=width*height;
        totlen=bmlen+40+776;
        iff_head[1]=totlen;
        iff_head[5]=(width<<16)|height;
        iff_head[7]=0x08000000;
        iff_body[1]=bmlen;
        fwrite(&iff_head[0],sizeof(iff_head),1,qdatei);
        fwrite(iff_cmap_ext,sizeof(iff_cmap_ext),1,qdatei);
        fwrite(iff_body,sizeof(iff_body),1,qdatei);
        memcpy(&dskwinpar,&winpar,sizeof(winpar));
        tabindex=((dskwinpar.resx/100)-2)+(dskwinpar.size-4)*3;
        dskwinpar.cornerx=cornerxval[tabindex];
        dskwinpar.cornery=corneryval[tabindex];
        dskwinpar.width=widthval[tabindex];
        dskwinpar.height=heightval[tabindex];
        dskwinpar.halftone=2;
        dskwinpar.bitspixel=8;
        glin=dskwinpar.height;
        rlin=0x200000L/(ULONG)dskwinpar.width;
        do
        { if (rlin>glin) rlin=glin;
                winpar.height=rlin;
                glin-=rlin;
                DoScsi(&cmd_mdon[0],6,(UWORD *)NULL,0,0);
                Delay(100);
                DoScsi(&cmd_dwin[0],10,(UWORD *)&dskwinpar,40,DIR_WRITE);
                DoScsi(&cmd_scan[0],6,(UWORD *)NULL,0,0);
                dskwinpar.cornery+=rlin;
                cmd_read[7]=(dskwinpar.width>>8)&0xff; cmd_read[8]=dskwinpar.width&0xff;
                for (i=0;i<dskwinpar.height;i++)
                { DoScsi(&cmd_read[0],10,(UWORD *)bufptr,dskwinpar.width,DIR_READ);
                        memset(planes,0,sizeof(planes));
                        for(k=0;k<6;k++)
                        { msk=64>>k;
                                for(j=0;j<dskwinpar.width;j++)
                                { if (*(bufptr+j)&msk)
                                                planes[k][j>>3]|=0x80>>(j&7);
                                }
                                fwrite(planes[k],dskwinpar.width,1,qdatei);
                        }
                }
        } while (glin);
        DoScsi(&cmd_mdoff[0],6,(UWORD *)NULL,0,0);
        fclose(qdatei);
}


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(void)
{ FILE *sdatei;
        ULONG memsize,memadd;
        UWORD i,t;
        UBYTE *loadptr;
        UBYTE planes[4000];
        UBYTE cnt,cval;
        UWORD bflag=1;

        if (filerequest("Lade 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("Kein 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*)"Kein Speicher");
                                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("Speichere 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,n3,n4,zeile,pwidth,bwidth,plins,blins;
        UBYTE linebuf[2000];

        if (numcols==16)
                { for (i=0;i<4;i++) plptr[i]=(UBYTE *)(rp->BitMap->Planes[i]+viewoffset);
                }
        else
                { for (i=0;i<2;i++) plptr[i]=(UBYTE *)(rp->BitMap->Planes[i]+viewoffset);
                        plptr[2]=0; plptr[3]=0;
                }
        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)&&(memheight>viewheight)&&(memwidth>viewwidth))
        { if (((memheight/2)<viewheight)&&((memwidth/2)<viewwidth)) sk=2;
                else if (((memheight/4)<viewheight)&&((memwidth/4)<viewwidth)) sk=4;
                else if (((memheight/8)<viewheight)&&((memwidth/8)<viewwidth)) sk=8;
                else if (((memheight/12)<viewheight)&&((memwidth/12)<viewwidth)) sk=12;
                vptr=memptr;
                vicr[0]=0; vicr[1]=vinc;
                for (i=2;i<13;i++) vicr[i]=vicr[i-1]+vinc;
                if (numcols==16) clrscr16(plptr[0],plptr[1],plptr[2],plptr[3],viewheight,(screenwidth>>3)-2);
                else clrscr4(plptr[0],plptr[1],viewheight,(screenwidth>>3)-2);
                zeile=0; vx=vy=0;
                if (memgray)
                switch (sk)
                { case 2: while(zeile<memheight)
                                                        { zeile+=2;
                                                                for (i=0;i<(memwidth>>1);i+=2)
                                                                { n1=n2=0; j=i;
                                                                        for (k=0;k<2;k++)
                                                                        { n1+=((*(vptr+j  )>>4)+(*(vptr+j  )&15));
                                                                                n2+=((*(vptr+j+1)>>4)+(*(vptr+j+1)&15));
                                                                                j+=vinc;
                                                                        }
                                                                        linebuf[i>>1]=((n1<<2)&0xf0)|(n2>>2);
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>4);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>4);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                vptr+=vicr[2];
                                                        }
                                                        break;
                        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);
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>5);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>5);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                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);
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>6);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>6);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                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);
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],(memwidth>>5)/3);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],(memwidth>>5)/3);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                vptr+=vicr[12];
                                                        }
                                                        break;
                }
                else
                switch (sk)
                { case 2: while(zeile<memheight)
                                                        { zeile+=2;
                                                                for (i=0;i<(memwidth>>3);i++)
                                                                { n1=numbits[ (*(vptr+i        ))>>6   ]+numbits[ (*(vptr+i+vicr[1]))>>6   ];
                                                                        if (n1==4) n1=3;
                                                                        n2=numbits[((*(vptr+i        ))>>4)&3]+numbits[((*(vptr+i+vicr[1]))>>4)&3];
                                                                        if (n2==4) n2=3;
                                                                        n3=numbits[((*(vptr+i        ))>>2)&3]+numbits[((*(vptr+i+vicr[1]))>>2)&3];
                                                                        if (n3==4) n3=3;
                                                                        n4=numbits[ (*(vptr+i        ))    &3]+numbits[ (*(vptr+i+vicr[1]))    &3];
                                                                        if (n4==4) n4=3;
                                                                        linebuf[i<<1]=(~((n1<<6)|(n2<<2)));
                                                                        linebuf[(i<<1)+1]=(~((n3<<6)|(n4<<2)));
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>4);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>4);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                vptr+=vicr[2];
                                                        }
                                                        break;
                        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));
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>5);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>5);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                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));
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],memwidth>>6);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],memwidth>>6);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                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));
                                                                }
                                                                if (numcols==16) vplanesep16(&linebuf[0],plptr[0],plptr[1],plptr[2],plptr[3],(memwidth>>5)/3);
                                                                else vplanesep4(&linebuf[0],plptr[0],plptr[1],(memwidth>>5)/3);
                                                                plptr[0]+=lineoffset; plptr[1]+=lineoffset; plptr[2]+=lineoffset; plptr[3]+=lineoffset;
                                                                vptr+=vicr[12];
                                                        }
                                                        break;
                }
        }
        else
        { vx=x&0xfff0; vy=y&0xfffe; sk=1;
                plins=viewheight; blins=0;
                if (plins>memheight)
                { plins=memheight;
                        blins=viewheight-plins;
                }
                pwidth=(screenwidth>>3)-2; bwidth=0;
                if (pwidth>(memwidth>>3))
                { pwidth=(memwidth>>3)&0xfffe;
                        bwidth=((screenwidth>>3)-2)-pwidth;
                }
                if (numcols==16)
                { if (memgray) grayview16(vptr,plptr[0],plptr[1],plptr[2],plptr[3],vinc,plins,blins,pwidth,bwidth);
                        else bwview16(vptr,plptr[0],plptr[1],plptr[2],plptr[3],vinc,plins,blins,pwidth,bwidth);
                }
                else
                { if (memgray) grayview4(vptr,plptr[0],plptr[1],vinc,plins,blins,pwidth,bwidth);
                        else bwview4(vptr,plptr[0],plptr[1],vinc,plins,blins,pwidth,bwidth);
                }
        }
}

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>viewwidth-1) t=viewwidth-1;
        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<=screenwidth)||(memheight<=screenheight)) MessReq("Bereich hat kleinste Größe"); */
        if (mf!=2) MessReq("Kein Bereich gewählt!");
        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<screenheight)
                { height=screenheight;
                        if ((wy1+height)>memheight) wy1=memheight-height;
                }
                if (width<screenwidth)
                { width=screenwidth;
                        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 *)"Kein Speicher");
                }
*/  }
}
