
 /*
  * im24.c
  *
  * (c) 1990 by Robert Junghans
  *
  * image/sprite-editor for programmers
  *
  */

 /* needed aztec-includes: */
#include <functions.h>

 /* some patterns to make the source shorter: */
#define PTT1 GADGHCOMP,RELVERIFY,BOOLGADGET
#define PTT2 50,19,PTT1,(APTR)&bor1,NULL
#define PTT3 100,12,PTT1,(APTR)&bor2,NULL

#define no_msg(a) (msg=(struct IntuiMessage *)GetMsg(a->UserPort))==NULL

 /* library-base-pointer: */
struct GfxBase *GfxBase=NULL;
struct IntuitionBase *IntuitionBase=NULL;

 /* some vars for intuition: */
struct Screen *scr=NULL;
struct ViewPort *vp;
struct Window *win1=NULL,*win2=NULL,*win3=NULL,*win4,*win5=NULL,*win6,*win7,
              *win8=NULL,*win9,*win10,*win11,*win12=NULL,*win13,*win14,
              *win15,*win16,*win17;
struct RastPort *rp1,*rp2,*rp3,*rp4,*rp5,*rp6,*rp7,*rp8,*rp9,*rp10,*rp11,
                *rp12,*rp13,*rp14,*rp15,*rp16,*rp17;
UWORD bline;

struct IntuiMessage *msg;
long sig;
ULONG class;
USHORT code,id;
struct Gadget *gad;
SHORT xpos,ypos;

 /* vars for disk operations: */
struct BitMap bmap;
struct FileHandle *fh=NULL;
char name[30];

 /* text-array to be saved as source-code: */
char src[44][58][4];

 /* counter etc.: */
int i,j,k,nr,xnr,ynr,end;
char buchst;

 /* settings: */
int colorl=1,colorr=0,anzeigen=0,xmin=5,ymin=12,xmax=502,ymax=185,bitmaps=4,
    aufl=1;
long breite=166,hoehe=58;

 /* the backup- and the user-palette: */
UWORD paletteb[]={
    0x000,0xfff,0xd00,0xf60,0xff0,0x7f7,0x0d0,0x091,
    0x777,0xbbb,0x4df,0x09f,0x00c,0x80a,0xc0d,0xf0f},
      paletteu[16];

 /* my special mouse pointer: */
USHORT mousedata[]={
    0x0000,0x0000,0x0500,0x0600,0x0500,0x0600,0x0500,0x0700,0x0880,0x0f80,
    0x1040,0x1880,0xe038,0xf058,0x0000,0xf078,0xe038,0x3040,0x1040,0x1880,
    0x0880,0x0700,0x0500,0x0200,0x0500,0x0600,0x0500,0x0600,0x0000,0x0000};
USHORT (*mouseptr)[]=NULL;

 /* the standard-80-font: */
struct TextAttr font={
    (STRPTR)"topaz.font",TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT};

 /* now the 'Kraut und Rueben'-part: */
SHORT pos1[]={-1,-1,50,-1,50,19,-1,19,-1,-1},
      pos2[]={0,0,99,0,99,11,0,11,0,0},
      pos3[]={0,0,122,0,122,9,0,9,0,0};

struct Border bor1={0,0,1,0,JAM1,5,pos1,NULL},
              bor2={0,0,1,0,JAM1,5,pos2,NULL},
              bor3={-1,-1,1,0,JAM1,5,pos3,NULL};

struct IntuiText text1={1,0,JAM1,41,0,NULL,(UBYTE *)"i",NULL},
                 text2={1,0,JAM1,9,11,NULL,(UBYTE *)"icon",&text1},
                 text3={1,0,JAM1,9,11,NULL,(UBYTE *)"info",NULL},
                 text4={1,0,JAM1,41,0,NULL,(UBYTE *)"f",NULL},
                 text5={1,0,JAM1,5,11,NULL,(UBYTE *)"flood",&text4},
                 text6={1,0,JAM1,41,0,NULL,(UBYTE *)"u",NULL},
                 text7={1,0,JAM1,9,11,NULL,(UBYTE *)"undo",&text6},
                 text8={1,0,JAM1,41,0,NULL,(UBYTE *)"d",NULL},
                 text9={1,0,JAM1,9,11,NULL,(UBYTE *)"disk",&text8},
                 text10={1,0,JAM1,41,0,NULL,(UBYTE *)"c",NULL},
                 text11={1,0,JAM1,1,11,NULL,(UBYTE *)"colors",&text10},
                 text12={1,0,JAM1,41,0,NULL,(UBYTE *)"p",NULL},
                 text13={1,0,JAM1,5,11,NULL,(UBYTE *)"prefs",&text12},
                 text14={1,0,JAM1,41,0,NULL,(UBYTE *)"e",NULL},
                 text15={1,0,JAM1,1,11,NULL,(UBYTE *)"extras",&text14},

                 text16={1,0,JAM1,34,2,NULL,(UBYTE *)"o.k.",NULL},

                 text17={1,0,JAM1,41,0,NULL,(UBYTE *)"s",NULL},
                 text18={1,0,JAM1,9,11,NULL,(UBYTE *)"show",&text17},
                 text19={1,0,JAM1,41,0,NULL,(UBYTE *)"c",NULL},
                 text20={1,0,JAM1,5,11,NULL,(UBYTE *)"clear",&text19},
                 text21={1,0,JAM1,41,0,NULL,(UBYTE *)"h",NULL},
                 text22={1,0,JAM1,1,11,NULL,(UBYTE *)"flip h",&text21},
                 text23={1,0,JAM1,41,0,NULL,(UBYTE *)"v",NULL},
                 text24={1,0,JAM1,1,11,NULL,(UBYTE *)"flip v",&text23},
                 text25={1,0,JAM1,41,0,NULL,(UBYTE *)"u",NULL},
                 text26={1,0,JAM1,13,11,NULL,(UBYTE *)"up1",&text25},
                 text27={1,0,JAM1,13,11,NULL,(UBYTE *)"up2",NULL},
                 text28={1,0,JAM1,13,11,NULL,(UBYTE *)"up3",NULL},
                 text29={1,0,JAM1,41,0,NULL,(UBYTE *)"d",NULL},
                 text30={1,0,JAM1,5,11,NULL,(UBYTE *)"down1",&text29},
                 text31={1,0,JAM1,5,11,NULL,(UBYTE *)"down2",NULL},
                 text32={1,0,JAM1,5,11,NULL,(UBYTE *)"down3",NULL},
                 text33={1,0,JAM1,41,0,NULL,(UBYTE *)"r",NULL},
                 text34={1,0,JAM1,1,11,NULL,(UBYTE *)"right1",&text33},
                 text35={1,0,JAM1,1,11,NULL,(UBYTE *)"right2",NULL},
                 text36={1,0,JAM1,1,11,NULL,(UBYTE *)"right3",NULL},
                 text37={1,0,JAM1,41,0,NULL,(UBYTE *)"l",NULL},
                 text38={1,0,JAM1,5,11,NULL,(UBYTE *)"left1",&text37},
                 text39={1,0,JAM1,5,11,NULL,(UBYTE *)"left2",NULL},
                 text40={1,0,JAM1,5,11,NULL,(UBYTE *)"left3",NULL},

                 text41={1,0,JAM1,1,0,NULL,(UBYTE *)"asm",NULL},
                 text42={1,0,JAM1,1,11,NULL,(UBYTE *)"sprite",&text41},
                 text43={1,0,JAM1,1,0,NULL,(UBYTE *)"c",NULL},
                 text44={1,0,JAM1,1,11,NULL,(UBYTE *)"sprite",&text43},
                 text45={1,0,JAM1,41,0,NULL,(UBYTE *)"a",&text41},
                 text46={1,0,JAM1,5,11,NULL,(UBYTE *)"image",&text45},
                 text47={1,0,JAM1,41,0,NULL,(UBYTE *)"c",&text43},
                 text48={1,0,JAM1,5,11,NULL,(UBYTE *)"image",&text47},
                 text49={1,0,JAM1,41,0,NULL,(UBYTE *)"p",NULL},
                 text50={1,0,JAM1,1,0,NULL,(UBYTE *)"pal",&text49},
                 text51={1,0,JAM1,9,11,NULL,(UBYTE *)"ilbm",&text50},

                 text52={1,0,JAM1,41,0,NULL,(UBYTE *)"l",NULL},
                 text53={1,0,JAM1,9,11,NULL,(UBYTE *)"ilbm",&text52},
                 text54={1,0,JAM1,41,0,NULL,(UBYTE *)"s",NULL},
                 text55={1,0,JAM1,9,11,NULL,(UBYTE *)"ilbm",&text54},
                 text56={1,0,JAM1,41,0,NULL,(UBYTE *)"1",NULL},
                 text57={1,0,JAM1,5,11,NULL,(UBYTE *)"plane",&text56},
                 text58={1,0,JAM1,41,0,NULL,(UBYTE *)"2",NULL},
                 text59={1,0,JAM1,1,11,NULL,(UBYTE *)"planes",&text58},
                 text60={1,0,JAM1,41,0,NULL,(UBYTE *)"3",NULL},
                 text61={1,0,JAM1,1,11,NULL,(UBYTE *)"planes",&text60},
                 text62={1,0,JAM1,41,0,NULL,(UBYTE *)"4",NULL},
                 text63={1,0,JAM1,1,11,NULL,(UBYTE *)"planes",&text62},

                 text64={1,0,JAM1,26,2,NULL,(UBYTE *)"cancel",NULL},
                 text65={1,0,JAM1,26,2,NULL,(UBYTE *)"(o).k.",NULL},

                 text66={1,0,JAM1,30,2,NULL,(UBYTE *)"hires",NULL},
                 text67={1,0,JAM1,26,2,NULL,(UBYTE *)"normal",NULL},
                 text68={1,0,JAM1,0,-8,NULL,(UBYTE *)"width :",NULL},
                 text69={1,0,JAM1,0,-8,NULL,(UBYTE *)"height :",NULL},

                 text70={1,0,JAM1,30,2,NULL,(UBYTE *)"reset",NULL},
                 text71={1,0,JAM1,-48,1,NULL,(UBYTE *)"red :",NULL},
                 text72={1,0,JAM1,-64,1,NULL,(UBYTE *)"green :",NULL},
                 text73={1,0,JAM1,-56,1,NULL,(UBYTE *)"blue :",NULL};

struct StringInfo string1={(UBYTE *)name,NULL,0,30,0,0,0,0,0,0,NULL,0,NULL};

struct PropInfo prop1={AUTOKNOB|FREEHORIZ,0,0,0,0,0,0,0,0,0,0},
                prop2={AUTOKNOB|FREEHORIZ,0,0,0x0469,0,0,0,0,0,0,0},

                prop3={AUTOKNOB|FREEHORIZ,0,0,0x1000,0,0,0,0,0,0,0},
                prop4={AUTOKNOB|FREEHORIZ,0,0,0x1000,0,0,0,0,0,0,0},
                prop5={AUTOKNOB|FREEHORIZ,0,0,0x1000,0,0,0,0,0,0,0};

struct Image image1,image2,image3,image4,image5;

struct Gadget gad1={NULL,585,12,PTT2,&text2,0,NULL,1,NULL},
              gad2={&gad1,585,34,PTT2,&text3,0,NULL,2,NULL},
              gad3={&gad2,585,56,PTT2,&text5,0,NULL,3,NULL},
              gad4={&gad3,585,78,PTT2,&text7,0,NULL,4,NULL},
              gad5={&gad4,585,100,PTT2,&text9,0,NULL,5,NULL},
              gad6={&gad5,585,122,PTT2,&text11,0,NULL,6,NULL},
              gad7={&gad6,585,144,PTT2,&text13,0,NULL,7,NULL},
              gad8={&gad7,585,166,PTT2,&text15,0,NULL,8,NULL},

              gad9={NULL,138,135,PTT3,&text16,0,NULL,9,NULL},

              gad10={NULL,16,16,PTT2,&text18,0,NULL,10,NULL},
              gad11={&gad10,70,16,PTT2,&text20,0,NULL,11,NULL},
              gad12={&gad11,124,16,PTT2,&text22,0,NULL,12,NULL},
              gad13={&gad12,178,16,PTT2,&text24,0,NULL,13,NULL},
              gad14={&gad13,16,40,PTT2,&text26,0,NULL,14,NULL},
              gad15={&gad14,70,40,PTT2,&text27,0,NULL,15,NULL},
              gad16={&gad15,124,40,PTT2,&text28,0,NULL,16,NULL},
              gad17={&gad16,16,62,PTT2,&text30,0,NULL,17,NULL},
              gad18={&gad17,70,62,PTT2,&text31,0,NULL,18,NULL},
              gad19={&gad18,124,62,PTT2,&text32,0,NULL,19,NULL},
              gad20={&gad19,16,84,PTT2,&text34,0,NULL,20,NULL},
              gad21={&gad20,70,84,PTT2,&text35,0,NULL,21,NULL},
              gad22={&gad21,124,84,PTT2,&text36,0,NULL,22,NULL},
              gad23={&gad22,16,106,PTT2,&text38,0,NULL,23,NULL},
              gad24={&gad23,70,106,PTT2,&text39,0,NULL,24,NULL},
              gad25={&gad24,124,106,PTT2,&text40,0,NULL,25,NULL},

              gad26={NULL,70,84,PTT2,&text42,0,NULL,26,NULL},
              gad27={&gad26,124,84,PTT2,&text44,0,NULL,27,NULL},
              gad28={&gad27,70,62,PTT2,&text46,0,NULL,28,NULL},
              gad29={&gad28,124,62,PTT2,&text48,0,NULL,29,NULL},
              gad30={&gad29,16,38,PTT2,&text51,0,NULL,30,NULL},

              gad31={&gad30,70,38,PTT2,&text53,0,NULL,31,NULL},
              gad32={&gad31,124,38,PTT2,&text55,0,NULL,32,NULL},
              gad33={&gad32,16,16,PTT2,&text57,0,NULL,33,NULL},
              gad34={&gad33,70,16,PTT2,&text59,0,NULL,34,NULL},
              gad35={&gad34,124,16,PTT2,&text61,0,NULL,35,NULL},
              gad36={&gad35,178,16,PTT2,&text63,0,NULL,36,NULL},

              gad37={NULL,84,15,120,10,GADGHCOMP,RELVERIFY|STRINGCENTER,
                  STRGADGET,(APTR)&bor3,NULL,NULL,0,(APTR)&string1,37,NULL},
              gad38={&gad37,12,29,PTT3,&text16,0,NULL,38,NULL},
              gad39={&gad38,120,29,PTT3,&text64,0,NULL,39,NULL},

              gad40={NULL,12,27,PTT3,&text64,0,NULL,40,NULL},
              gad41={&gad40,120,27,PTT3,&text65,0,NULL,41,NULL},

              gad42={NULL,100,27,PTT3,&text16,0,NULL,42,NULL},

              gad43={NULL,24,15,PTT3,&text66,0,NULL,43,NULL},
              gad44={&gad43,132,15,PTT3,&text67,0,NULL,44,NULL},
              gad45={&gad44,12,39,200,10,GADGHCOMP,RELVERIFY,PROPGADGET,
                  (APTR)&image1,NULL,&text68,0,(APTR)&prop1,45,NULL},
              gad46={&gad45,12,61,200,10,GADGHCOMP,RELVERIFY,PROPGADGET,
                  (APTR)&image2,NULL,&text69,0,(APTR)&prop2,46,NULL},
              gad47={&gad46,24,77,PTT3,&text16,0,NULL,47,NULL},
              gad48={&gad47,132,77,PTT3,&text64,0,NULL,48,NULL},

              gad49={NULL,15,17,PTT3,&text16,0,NULL,49,NULL},
              gad50={&gad49,15,30,PTT3,&text64,0,NULL,50,NULL},
              gad51={&gad50,15,43,PTT3,&text70,0,NULL,51,NULL},
              gad52={&gad51,190,18,100,10,GADGHCOMP,RELVERIFY,PROPGADGET,
                  (APTR)&image3,NULL,&text71,0,(APTR)&prop3,52,NULL},
              gad53={&gad52,190,31,100,10,GADGHCOMP,RELVERIFY,PROPGADGET,
                  (APTR)&image4,NULL,&text72,0,(APTR)&prop4,53,NULL},
              gad54={&gad53,190,44,100,10,GADGHCOMP,RELVERIFY,PROPGADGET,
                  (APTR)&image5,NULL,&text73,0,(APTR)&prop5,54,NULL};

struct NewScreen ns={
    0,0,640,200,4,0,1,HIRES,CUSTOMSCREEN,&font,
    (UBYTE *)"ImageEditor v2.4",NULL,NULL};

struct NewWindow nw1={
    0,11,640,189,0,1,MOUSEBUTTONS|GADGETUP|CLOSEWINDOW|VANILLAKEY,
    WINDOWCLOSE|SMART_REFRESH|ACTIVATE|RMBTRAP,&gad8,NULL,
    (UBYTE *)"draw window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw2={
    0,129,174,71,0,1,0,SMART_REFRESH|BACKDROP,NULL,NULL,
    (UBYTE *)"undo picture",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw3={
    174,129,174,71,0,1,0,SMART_REFRESH|BACKDROP,NULL,NULL,
    (UBYTE *)"origin picture",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw4={
    137,29,376,153,0,1,GADGETUP,SMART_REFRESH|ACTIVATE,&gad9,NULL,
    (UBYTE *)"info window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw5={
    0,11,166,58,0,1,0,SUPER_BITMAP|BORDERLESS|BACKDROP,NULL,NULL,
    NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw6={
    0,11,128+60+48,10,0,1,MOUSEBUTTONS|CLOSEWINDOW|VANILLAKEY,
    WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SMART_REFRESH|ACTIVATE|RMBTRAP,
    NULL,NULL,(UBYTE *)"ImageEditor v2.4",NULL,NULL,0,0,0,0,WBENCHSCREEN},
                 nw7={
    198,33,244,134,0,1,GADGETUP|CLOSEWINDOW|VANILLAKEY,
    WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE,&gad25,NULL,
    (UBYTE *)"extras window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw8={
    0,127,176,73,0,1,CLOSEWINDOW,WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH,
    NULL,NULL,(UBYTE *)"show window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw9={
    0,11,498,9,0,1,0,SMART_REFRESH|BORDERLESS|BACKDROP,
    NULL,NULL,NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw10={
    0,11,18,174,0,1,0,SMART_REFRESH|BORDERLESS|BACKDROP,
    NULL,NULL,NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw11={
    198,44,244,112,0,1,GADGETUP|CLOSEWINDOW|VANILLAKEY,
    WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE,&gad36,NULL,
    (UBYTE *)"disk window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw12={
    0,11,166,58,0,1,0,SUPER_BITMAP|BORDERLESS|BACKDROP,NULL,NULL,
    NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw13={
    204,76,232,47,0,1,GADGETUP,WINDOWDRAG|SMART_REFRESH|ACTIVATE,
    &gad39,NULL,(UBYTE *)"edit name",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw14={
    0,0,232,45,0,1,GADGETUP|VANILLAKEY,WINDOWDRAG|SMART_REFRESH|ACTIVATE,
    &gad41,NULL,(UBYTE *)"last request",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw15={
    170,77,300,45,0,1,GADGETUP,WINDOWDRAG|SMART_REFRESH|ACTIVATE,
    &gad42,NULL,(UBYTE *)"aborting",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw16={
    192,51,256,97,0,1,GADGETUP|CLOSEWINDOW|VANILLAKEY|INTUITICKS,
    WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE,&gad48,NULL,
    (UBYTE *)"prefs window",NULL,NULL,0,0,0,0,CUSTOMSCREEN},
                 nw17={
    157,68,326,63,0,1,GADGETUP|CLOSEWINDOW|VANILLAKEY|INTUITICKS,
    WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE,&gad54,NULL,
    (UBYTE *)"colors window",NULL,NULL,0,0,0,0,CUSTOMSCREEN};

main()
{
     /* init the lib-base-pointer by opening libs: */
    if((GfxBase=(struct GfxBase *)
        OpenLibrary("graphics.library",0L))==NULL)
        ende();
    if((IntuitionBase=(struct IntuitionBase *)
        OpenLibrary("intuition.library",0L))==NULL)
        ende();

     /* my-mouse-pointer-data in chip-mem: */
    if((mouseptr=AllocMem(60L,MEMF_CHIP))==NULL) ende();
    CopyMem(mousedata,mouseptr,60L);

     /* open the screen: */
    if((scr=OpenScreen(&ns))==NULL) ende();
    vp=&scr->ViewPort;

     /* init and set the user-palette: */
    for(i=0;i<16;i++)
        paletteu[i]=paletteb[i];
    LoadRGB4(vp,paletteu,16L);

     /* open the main window: */
    nw1.Screen=scr;
    if((win1=OpenWindow(&nw1))==NULL) ende();
    SetPointer(win1,mouseptr,13L,16L,-7L,-6L);
    rp1=win1->RPort;
    bline=rp1->TxBaseline;
    SetAPen(rp1,1L);

     /* border the draw-area: */
    rectangle(rp1,xmin-1,ymin-1,xmax+1,ymax+1);

     /* draw the color-gadgets: */
    for(i=0;i<16;i++)
        rectangle(rp1,531,11+i*11,555,20+i*11);
    for(i=0;i<16;i++) {
        SetAPen(rp1,(long)i);
        RectFill(rp1,532L,(long)12+i*11,554L,(long)19+i*11);
    }
    SetAPen(rp1,1L);

     /* show the user the act colors: */
    pfeil('l',1);
    pfeil('r',0);

     /* open the undo-window: */
    nw2.Screen=scr;
    if((win2=OpenWindow(&nw2))==NULL) ende();
    rp2=win2->RPort;

     /* open the origin-size-window: */
    nw3.Screen=scr;
    if((win3=OpenWindow(&nw3))==NULL) ende();
    rp3=win3->RPort;

     /* take and execute commands: */
    FOREVER {
        if(anzeigen)
            while(no_msg(win1) && no_msg(win8))
                sig=Wait(1L<<win1->UserPort->mp_SigBit |
                     1L<<win8->UserPort->mp_SigBit);
        else
            while(no_msg(win1))
                WaitPort(win1->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(anzeigen && sig==1L<<win8->UserPort->mp_SigBit) {
            CloseWindow(win8);
            win8=NULL;
            anzeigen=0;
        } else {
            if(class==MOUSEBUTTONS)
                if(code==SELECTDOWN || code==MENUDOWN) {
                    xpos=win1->MouseX;
                    ypos=win1->MouseY;
                    if(xpos>=xmin && xpos<=xmax && ypos>=ymin && ypos<=ymax)
                        paint();
                    else if(xpos>=531 && xpos<=555 && ypos>=11 && ypos<=185)
                        if((ypos-11)%11!=10) {
                            nr=(ypos-11)/11;
                            buchst=code==SELECTDOWN?'l':'r';
                            new_color(buchst,nr);
                        }
                }
            if(class==GADGETUP) {
                id=gad->GadgetID;
                switch(id) {
                case 1:
                    if(!iconify()) alert();
                    break;
                case 2:
                    info();
                    break;
                case 3:
                    if(!flood()) alert();
                    break;
                case 4:
                    undo();
                    break;
                case 5:
                    if(!disk()) alert();
                    break;
                case 6:
                    if(!colors()) alert();
                    break;
                case 7:
                    if(!prefs()) alert();
                    break;
                case 8:
                    if(!extras()) alert();
                    break;
                }
            }
            if(class==VANILLAKEY)
                switch(code) {
                case 'i':
                    if(!iconify()) alert();
                    break;
                case 'f':
                    if(!flood()) alert();
                    break;
                case 'u':
                    undo();
                    break;
                case 'd':
                    if(!disk()) alert();
                    break;
                case 'c':
                    if(!colors()) alert();
                    break;
                case 'p':
                    if(!prefs()) alert();
                    break;
                case 'e':
                    if(!extras()) alert();
                    break;
                case 'q':
                    if(anzeigen) {
                        CloseWindow(win8);
                        win8=NULL;
                        anzeigen=0;
                    } else
                        class=CLOSEWINDOW;
                    break;
                }
            if(class==CLOSEWINDOW)
                if(request())
                    ende();
        }
    }

}

ende()
 /* this function will close all basic windows, the screen, the libs and
  * will also release the 60 bytes of chip-memory for my mouse pointer and
  * then exit the program
  */
{
    if(win8) CloseWindow(win8);
    if(win3) CloseWindow(win3);
    if(win2) CloseWindow(win2);
    if(win1) CloseWindow(win1);
    if(scr) CloseScreen(scr);

    if(mouseptr) FreeMem(mouseptr,60L);

    if(IntuitionBase) CloseLibrary(IntuitionBase);
    if(GfxBase) CloseLibrary(GfxBase);

    exit(0);
}

rectangle(rp,x1,y1,x2,y2)
 /* this function is drawing a rectangle in the wished rastport at the
  * wished position
  */
    struct RastPort *rp;
    int x1,y1,x2,y2;
{
    Move(rp,(long)x1,(long)y1);
    Draw(rp,(long)x2,(long)y1);
    Draw(rp,(long)x2,(long)y2);
    Draw(rp,(long)x1,(long)y2);
    Draw(rp,(long)x1,(long)y1);
}

pfeil(side,nr)
 /* this function will mark the actual left/right color with a visible
  * arrow; passed vars: char side is 'l' for left color or anything else
  * (what about 'r'?) for the right color, int nr is the color number
  */
    char side;
    int nr;
{
    long in,out;

    if(side=='l') {
        in=529;
        out=505;
    } else {
        in=557;
        out=581;
    }

    Move(rp1,out,(long)11+nr*11);
    Draw(rp1,in,(long)16+nr*11);
    Move(rp1,out,(long)11+nr*11);
    Draw(rp1,out,(long)21+nr*11);
    Draw(rp1,in,(long)16+nr*11);
}

new_color(side,nr)
 /* if the user changes a color, this function will be called with the
  * side (char: 'l' for left or anything else for right) and the color
  * number passed; one of the vars colorl/colorr will be set; this function
  * will delete the old arrow and draw a new one
  */
    char side;
    int nr;
{
    SetAPen(rp1,0L);
    pfeil(side,side=='l'?colorl:colorr);

    if(side=='l')
        colorl=nr;
    else
        colorr=nr;
    SetAPen(rp1,1L);
    pfeil(side,nr);
}

paint()
 /* this function will be called when the user pushed a mouse button in the
  * draw-area; the actual position is set (in the main-function) in the vars
  * xpos and ypos; this function will copy the actual picture in the undo-
  * window, then select the draw color (dependind on which mouse button was
  * pushed) and then draw the actual point; if now the user moves the mouse
  * in the draw-area, this function will always draw a line from the last
  * point it remember (last point drawn) to the actual position; if the user
  * moves the pointer out of bounds, the function will start again with only
  * one point (when the user starts drawing or gets out of bounds, the var
  * xold (which remembers the last x-position) is set to an impossible value
  * (1000) so the next time no line will be drawn); after every point or line
  * this function takes a message from the draw-window-userport to see the
  * new actual pointer position and to check if the user is still pressing
  * the mouse button
  */
{
    int xold,yold,xdiff,ydiff,xabs,yabs;

    update();

    buchst=code==SELECTDOWN?'l':'r';

    xold=1000;
    do {
        xnr=(xpos-5)/(3*aufl);
        ynr=(ypos-12)/3;
        if(xnr>=0 && xnr<breite && ynr>=0 && ynr<hoehe) {
            if(xold!=1000) {
                xdiff=xnr-xold;
                ydiff=ynr-yold;
                xabs=ABS(xdiff);
                yabs=ABS(ydiff);
                if(xabs<=1 && yabs<=1)
                    pixel(buchst,xnr,ynr);
                else
                    if(xabs>=yabs) {
                        if(xdiff>0)
                            for(i=1;i<=xdiff;i++)
                                pixel(buchst,xold+i,yold+ydiff*i/xdiff);
                        else
                            for(i=-1;i>=xdiff;i--)
                                pixel(buchst,xold+i,yold+ydiff*i/xdiff);
                    } else {
                        if(ydiff>0)
                            for(i=1;i<=ydiff;i++)
                                pixel(buchst,xold+xdiff*i/ydiff,yold+i);
                        else
                            for(i=-1;i>=ydiff;i--)
                                pixel(buchst,xold+xdiff*i/ydiff,yold+i);
                    }

            }
            else
                pixel(buchst,xnr,ynr);

            xold=xnr;
            yold=ynr;
        } else
            xold=1000;

        msg=(struct IntuiMessage *)GetMsg(win1->UserPort);
        if(msg) {
            class=msg->Class;
            code=msg->Code;
            ReplyMsg(msg);
        }

        xpos=win1->MouseX;
        ypos=win1->MouseY;
    } while(!(class==MOUSEBUTTONS && code==SELECTUP || code==MENUUP));
}

pixel(buchst,x,y)
 /* this function is used to draw; it sets the draw-colors in the needed
  * rastports and then draw a rectangle in the draw-window, one or two points
  * in the origin-size-window and maybe also one or two points in the show-
  * window (two points are drawn when we are drawing in the lores-mode; the
  * mode can be set in the pref(erence)s-part)
  */
    char buchst;
    int x,y;
{
    long col;

    col=buchst=='l'?colorl:colorr;

    SetAPen(rp1,col);
    RectFill(rp1,(long)5+x*3*aufl,(long)12+y*3,
        (long)4+3*aufl+x*3*aufl,(long)14+y*3);

    SetAPen(rp3,col);
    WritePixel(rp3,(long)4+x*aufl,(long)11+y);
    if(aufl==2)
        WritePixel(rp3,(long)5+x*aufl,(long)11+y);

    if(anzeigen) {
        SetAPen(rp8,col);
        WritePixel(rp8,(long)5+x*aufl,(long)12+y);
        if(aufl==2)
            WritePixel(rp8,(long)6+x*aufl,(long)12+y);
    }
}

text(rp,x,y,str)
 /* this function is writing the wished text in the wished rastport at the
  * wished position;
  * remark: the var bline is initialized in the main-function after opening
  *         the draw-window and it contains the number of lines the text
  *         would be drawn higher than wished
  */
    struct RastPort *rp;
    int x,y;
    char *str;
{
    Move(rp,(long)x,(long)y+bline);
    Text(rp,str,(long)strlen(str));
}

update()
 /* this function destroys the undo-picture by overwriting this with the
  * origin-picture; it is called e.g. when the user draws the next point
  */
{
    ClipBlit(rp3,4L,11L,rp2,4L,11L,breite*aufl,hoehe,(long)0xc0);
}

undo()
 /* this function will undo the last user-action by bringing the last
  * 'saved' picture on the draw-window
  */
{
    reverse(win1,4);

    ClipBlit(rp2,4L,11L,rp3,4L,11L,breite*aufl,hoehe,(long)0xc0);
    if(anzeigen)
        ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);
    erase();
    get_msgs();

    reverse(win1,4);
}

erase()
 /* because the undo-window is smaller than the draw-window (to save chip-
  * memory) after every undo (or after iconifying, when the picture is also
  * remembered in small-size) we must erase the picture, what this function
  * is doing (first of all the small-picture is copied in the draw-area in
  * the upper left corner and than this function is called)
  */
{
    for(i=breite*aufl-1;i>=0;i--) {
        ClipBlit(rp3,(long)4+i,11L,rp1,(long)5+i*3,12L,
            1L,hoehe,(long)0xc0);
        ClipBlit(rp1,(long)5+i*3,12L,rp1,(long)6+i*3,12L,
            1L,hoehe,(long)0xc0);
        ClipBlit(rp1,(long)5+i*3,12L,rp1,(long)7+i*3,12L,
            1L,hoehe,(long)0xc0);
    }
    for(i=hoehe-1;i>=0;i--) {
        ClipBlit(rp1,5L,(long)12+i,rp1,5L,(long)12+i*3,
            breite*3*aufl,1L,(long)0xc0);
        ClipBlit(rp1,5L,(long)12+i*3,rp1,5L,(long)13+i*3,
            breite*3*aufl,1L,(long)0xc0);
        ClipBlit(rp1,5L,(long)12+i*3,rp1,5L,(long)14+i*3,
            breite*3*aufl,1L,(long)0xc0);
    }
}

info()
 /* this function is opening a window and displaying some informations to
  * this program
  */
{
    reverse(win1,2);

    nw4.Screen=scr;
    if((win4=OpenWindow(&nw4))==NULL)
        alert();
    else {
        SetPointer(win4,mouseptr,13L,16L,-7L,-6L);
        rp4=win4->RPort;

        SetAPen(rp4,2L);
        text(rp4,124,15,"ImageEditor v2.4");
        SetAPen(rp4,1L);
        text(rp4,88,27,"© 1990 by Robert Junghans");
        text(rp4,84,39,"date of release: 20.Apr.90");
        SetAPen(rp4,2L);
        text(rp4,12,51,"Tool");
        SetAPen(rp4,1L);
        text(rp4,52,51,"for programmers interested in graphics.");
        text(rp4,84,59,"This program is");
        SetAPen(rp4,2L);
        text(rp4,212,59,"Shareware.");
        SetAPen(rp4,1L);
        text(rp4,52,67,"If you use it please send $5.00 to");
        text(rp4,128,75,"Robert Junghans");
        text(rp4,112,83,"Agnes Straub Weg 10");
        text(rp4,132,91,"1000 Berlin 47");
        text(rp4,140,99,"West Germany");
        text(rp4,60,111,"Improvement suggestions welcome.");
        text(rp4,64,123,"[ see");
        SetAPen(rp4,2L);
        text(rp4,112,123,"im24.doc");
        SetAPen(rp4,1L);
        text(rp4,184,123,"for more infos ]");

        WaitPort(win4->UserPort);
        CloseWindow(win4);

        get_msgs();
    }
    reverse(win1,2);
}

get_msgs()
 /* if a time-intensive function was called (e.g. undo or disk etc.) so the
  * user could activate some draw-window-gadgets in the time the function
  * was executed; to not let him wait until all 'clicked' functions will be
  * also executed, this function is called and it is 'clearing' the user-
  * ports of the draw-window and maybe of the show-window of all messages
  */
{
    message(win1);
    if(anzeigen) message(win8);
}

message(win)
 /* this function will 'take' all messages send to the wished window and
  * reply them
  */
    struct Window *win;
{
    while(msg=(struct IntuiMessage *)GetMsg(win->UserPort))
        ReplyMsg(msg);
}

alert()
 /* this simple function displays an alert looking a little bit like
  * the well known meditation from india; the best way to continue is
  * to push the left mouse button; this function will be called when an
  * other function can't get the memory it needs and must be aborted
  */
{
    static BYTE alert[]={
        0,248,15,"Not enough memory!",1,
        0,176,28,"The actual function will be aborted!",1,
        0,128,41,"Please press the left mouse button to continue..",0};

    DisplayAlert(RECOVERY_ALERT,alert,53L);
}

reverse(win,id)
 /* this function will search in the wished window-gadget-list for the
  * gadget with the wished id and then reverse it; if a gadget with the
  * given id does not exist in the list of the wished window, no gadget
  * will be inverted
  */
    struct Window *win;
    int id;
{
    struct RastPort *rp;
    struct Gadget *gad;
    int done;

    rp=win->RPort;
    gad=win->FirstGadget;
    done=0;

    if(gad)
        do {
            if(gad->GadgetID==id) {
                SetDrMd(rp,JAM1|COMPLEMENT);
                RectFill(rp,(long)gad->LeftEdge,(long)gad->TopEdge,
                    (long)gad->LeftEdge+gad->Width-1,
                    (long)gad->TopEdge+gad->Height-1);
                SetDrMd(rp,JAM1);
                done=1;
            }
            gad=gad->NextGadget;
        } while(gad && !done);
}

iconify()
 /* if the user needs the chip-memory which is used by im24 he must not quit
  * the program; he can also iconify it, i.e. the windows and the screen from
  * im24 will be closed and im24 will open a small window on the workbench
  * screen and the user can run another programs which need chip-memory;
  * after this the user just have to activate the im24-window and push the
  * right mouse button and im24 will open screen and windows and display the
  * old picture so the user can work with im24 again;
  * remark: by iconifying you will lose the undo-picture!
  * remark: the iconified-wb-window has also a closewindow-gadget, so you
  *         can also quit im24 when it is iconified
  * remark: the anzeigen-flag will be cleared even if it was set
  */
{
    struct BitMap bmap;

    end=0;
    reverse(win1,1);

    InitBitMap(&bmap,4L,breite*aufl,hoehe);
    for(i=0;i<4;i++)
        if((bmap.Planes[i]=AllocRaster(breite*aufl,hoehe))==NULL) {
            for(j=0;j<i;j++)
                FreeRaster(bmap.Planes[j],breite*aufl,hoehe);
            reverse(win1,1);
            return(0);
        }

    nw5.Width=breite*aufl;
    nw5.Height=hoehe;
    nw5.Screen=scr;
    nw5.BitMap=&bmap;
    if((win5=OpenWindow(&nw5))==NULL) {
        for(i=0;i<4;i++)
            if(bmap.Planes[i])
                FreeRaster(bmap.Planes[i],breite*aufl,hoehe);
        reverse(win1,1);
        return(0);
    }
    rp5=win5->RPort;

    ClipBlit(rp3,4L,11L,rp5,0L,0L,breite*aufl,hoehe,(long)0xc0);

    if((win6=OpenWindow(&nw6))==NULL) {
        CloseWindow(win5);

        for(i=0;i<4;i++)
            if(bmap.Planes[i])
                FreeRaster(bmap.Planes[i],breite*aufl,hoehe);
        reverse(win1,1);
        return(0);
    }
    SetPointer(win6,mouseptr,13L,16L,-7L,-6L);

    close_all();

    do {
        while(no_msg(win6))
            WaitPort(win6->UserPort);

        class=msg->Class;
        code=msg->Code;
        ReplyMsg(msg);

        if(class==VANILLAKEY)
            if(code=='q')
                class=CLOSEWINDOW;
        if(class==CLOSEWINDOW)
            if(request()) {
                for(i=0;i<4;i++)
                    FreeRaster(bmap.Planes[i],breite*aufl,hoehe);
                CloseWindow(win6);

                ende();
            }
        if(class==MOUSEBUTTONS)
            if(code==MENUDOWN) {

                if((scr=OpenScreen(&ns))==NULL) {
                    alert();
                    continue;
                }
                vp=&scr->ViewPort;

                LoadRGB4(vp,paletteu,16L);

                nw1.Screen=scr;
                if((win1=OpenWindow(&nw1))==NULL) {
                    close_all();
                    alert();
                    continue;
                }
                SetPointer(win1,mouseptr,13L,16L,-7L,-6L);
                reverse(win1,1);
                rp1=win1->RPort;
                SetAPen(rp1,1L);

                rectangle(rp1,xmin-1,ymin-1,xmax+1,ymax+1);

                for(i=0;i<16;i++)
                    rectangle(rp1,531,11+i*11,555,20+i*11);
                for(i=0;i<16;i++) {
                    SetAPen(rp1,(long)i);
                    RectFill(rp1,532L,(long)12+i*11,554L,(long)19+i*11);
                }
                SetAPen(rp1,1L);

                pfeil('l',colorl);
                pfeil('r',colorr);

                nw2.Screen=scr;
                if((win2=OpenWindow(&nw2))==NULL) {
                    close_all();
                    alert();
                    continue;
                }
                rp2=win2->RPort;

                nw3.Screen=scr;
                if((win3=OpenWindow(&nw3))==NULL) {
                    close_all();
                    alert();
                    continue;
                }
                rp3=win3->RPort;

                BltBitMapRastPort(&bmap,0L,0L,rp3,4L,11L,
                    breite*aufl,hoehe,(long)0xc0);

                for(i=0;i<4;i++)
                    FreeRaster(bmap.Planes[i],breite*aufl,hoehe);
                CloseWindow(win6);

                anzeigen=0;

                update();
                erase();

                get_msgs();
                end=1;
            }
    } while(!end);

    reverse(win1,1);
    return(1);
}

close_all()
 /* this function is closing the screen-windows and the screen to get
  * as much chip-memory as possible free; it also sets the window- and
  * screen-pointer to null, because this pointer are also flags if the
  * windows and the screen are open (to avoid closing them twice)
  */
{
    if(win8) CloseWindow(win8);
    if(win5) CloseWindow(win5);
    if(win3) CloseWindow(win3);
    if(win2) CloseWindow(win2);
    if(win1) CloseWindow(win1);
    if(scr) CloseScreen(scr);

    win8=win5=win3=win2=win1=scr=NULL;
}

request()
 /* this function will ask the user if he wants to quit the program;
  * it returns 1 if he wants to quit, 0 if not
  */
{
    int response;

    if(scr) {
        nw14.Screen=scr;
        nw14.Type=CUSTOMSCREEN;
    } else
        nw14.Type=WBENCHSCREEN;

    if((win14=OpenWindow(&nw14))==NULL)
        return(0);
    SetPointer(win14,mouseptr,13L,16L,-7L,-6L);
    rp14=win14->RPort;
    SetAPen(rp14,1L);

    text(rp14,32,15,"really quit the prg.?");

    while(no_msg(win14))
        WaitPort(win14->UserPort);

    class=msg->Class;
    code=msg->Code;
    gad=(struct Gadget *)msg->IAddress;
    ReplyMsg(msg);

    if(class==GADGETUP)
        response=gad->GadgetID==41;
    if(class==VANILLAKEY)
        response=code=='o';

    CloseWindow(win14);
    return(response);
}

flood()
 /* this function will flood a area using the graphics.library-function;
  * first of all the function is waiting for a message, it is handling only
  * three messages: the pressing of the flood-gadget or the pressing of the
  * f-key to end the function immediately (e.g. when the user choose this
  * function and now doesn't want to flood anything) or the pushing of a
  * mouse button in the draw-area, then a temporary raster will be allocated
  * (important for the graphics.library-function) and initialized; then the
  * origin-size-picture will be copied in the undo-window and the draw color
  * will be choosed; then our temporary raster will be assigned to the ori-
  * gin-size-window and we will border the picture-area with an color diffe-
  * rent from the color under the mouse pointer (so we won't flood the whole
  * window) and then the graphics.library-function will be called; after this
  * the same (assignment and flooding) will happen to the draw-window; then
  * the raster-memory will be given back to the system and last the picture
  * will be copied to the show-window (when this exists)
  */
{
    long col,col2;
    struct TmpRas tras;
    APTR buffer=NULL;
    int brei,hoe;

    end=0;
    reverse(win1,3);

    do {
        while(no_msg(win1))
            WaitPort(win1->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(class==MOUSEBUTTONS)
            if(code==SELECTDOWN || code==MENUDOWN) {
                xpos=win1->MouseX;
                ypos=win1->MouseY;
                if(xpos>=xmin && xpos<=xmax && ypos>=ymin && ypos<=ymax) {

                    if((buffer=AllocRaster(640L,200L))==NULL) {
                        reverse(win1,3);
                        return(0);
                    }
                    InitTmpRas(&tras,buffer,(long)RASSIZE(640,200));

                    update();

                    xnr=(xpos-5)/(3*aufl);
                    ynr=(ypos-12)/3;

                    col=code==SELECTDOWN?colorl:colorr;
                    col2=ReadPixel(rp1,(long)xpos,(long)ypos)+1;

                    rp3->TmpRas=&tras;
                    SetAPen(rp3,col2);
                    brei=breite;
                    hoe=hoehe;
                    rectangle(rp3,3,10,4+brei*aufl,11+hoe);

                    SetAPen(rp3,col);
                    Flood(rp3,1L,(long)xnr*aufl+4,(long)ynr+11);
                    rp3->TmpRas=NULL;

                    rp1->TmpRas=&tras;
                    SetAPen(rp1,col2);
                    rectangle(rp1,xmin-1,ymin-1,xmax+1,ymax+1);
                    SetAPen(rp1,col);
                    Flood(rp1,1L,(long)xpos,(long)ypos);
                    SetAPen(rp1,1L);
                    rectangle(rp1,xmin-1,ymin-1,xmax+1,ymax+1);
                    rp1->TmpRas=NULL;

                    FreeRaster(buffer,640L,200L);

                    if(anzeigen)
                        ClipBlit(rp3,4L,11L,rp8,5L,12L,
                            breite*aufl,hoehe,(long)0xc0);

                    get_msgs();

                    end=1;
                }
            }
        if(class==GADGETUP)
            end=gad->GadgetID==3;
        if(class==VANILLAKEY)
            if(code=='f') {
                class=0;
                end=1;
            }

    } while(!end);

    reverse(win1,3);
    return(1);
}

extras()
 /* in the here opened extras-window the user can open the show-window,
  * clear the draw-area or flip and move the picture
  */
{
    reverse(win1,8);
    gad11.NextGadget=anzeigen?NULL:&gad10;

    nw7.Screen=scr;
    if((win7=OpenWindow(&nw7))==NULL)
        return(0);
    SetPointer(win7,mouseptr,13L,16L,-7L,-6L);
    rp7=win7->RPort;
    SetAPen(rp7,1L);
    rectangle(rp7,12,37,177,127);

    do {
        while(no_msg(win7))
            WaitPort(win7->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(class==GADGETUP) {
            id=gad->GadgetID;
            switch(id) {
            case 10:
                if(!show()) alert();
                break;
            case 11:
                clear();
                break;
            case 12:
                if(!mirror()) alert();
                break;
            case 13:
                if(!upside()) alert();
                break;
            case 14:
            case 15:
            case 16:
                updown(id-13);
                break;
            case 17:
            case 18:
            case 19:
                updown(16-id);
                break;
            case 20:
            case 21:
            case 22:
                rightleft(id-19);
                break;
            case 23:
            case 24:
            case 25:
                rightleft(22-id);
                break;
            }
        }
        if(class==VANILLAKEY)
            switch(code) {
            case 's':
                if(!show()) alert();
                break;
            case 'c':
                clear();
                break;
            case 'h':
                if(!mirror()) alert();
                break;
            case 'v':
                if(!upside()) alert();
                break;
            case 'u':
                updown(1);
                break;
            case 'd':
                updown(-1);
                break;
            case 'r':
                rightleft(1);
                break;
            case 'l':
                rightleft(-1);
                break;
            case 'q':
                class=CLOSEWINDOW;
                break;
            }
    } while(class!=CLOSEWINDOW);

    class=0;
    CloseWindow(win7);
    reverse(win1,8);
    get_msgs();
    return(1);
}

show()
 /* this function will open the show-window, copy the picture from the
  * origin-size-window and hide the show-gadget in the extras-window;
  * the anzeigen-flag will be set
  */
{
    int brei,hoe;

    nw8.Screen=scr;
    if((win8=OpenWindow(&nw8))==NULL)
        return(0);
    SetPointer(win8,mouseptr,13L,16L,-7L,-6L);
    rp8=win8->RPort;
    SetAPen(rp8,1L);
    brei=breite;
    hoe=hoehe;
    rectangle(rp8,4,11,5+brei*aufl,12+hoe);
    ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);
    anzeigen=1;

    gad11.NextGadget=NULL;
    SetAPen(rp7,0L);
    RectFill(rp7,15L,15L,66L,35L);

    return(1);
}

clear()
 /* this function is copying the actual picture in the undo-window,
  * then the whole drawing area is filled with the 'left color'; the
  * origin-size-window and the show-window are filled too
  */
{
    update();

    SetAPen(rp1,(long)colorl);
    RectFill(rp1,(long)xmin,(long)ymin,(long)xmax,(long)ymax);

    SetAPen(rp3,(long)colorl);
    RectFill(rp3,4L,11L,3+breite*aufl,10+hoehe);

    if(anzeigen) {
        SetAPen(rp8,(long)colorl);
        RectFill(rp8,5L,12L,(long)4+breite*aufl,(long)11+hoehe);
    }
}

mirror()
 /* this function is flipping (horizonthal) the whole picture;
  * remark: the undo-picture gets lost
  */
{
    reverse(win7,12);

    nw10.Screen=scr;
    if((win10=OpenWindow(&nw10))==NULL)
        alert();
    else {
        rp10=win10->RPort;

        for(i=0;i<breite/2;i++) {
            ClipBlit(rp1,(long)5+i*3*aufl,12L,rp10,0L,0L,
                (long)3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp1,(long)5+(breite-i-1)*3*aufl,12L,rp1,
                (long)5+i*3*aufl,12L,(long)3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp1,(long)5+(breite-i-1)*3*aufl,12L,
                (long)3*aufl,hoehe*3,(long)0xc0);

            ClipBlit(rp3,(long)4+i*aufl,11L,rp10,0L,0L,
                (long)aufl,hoehe,(long)0xc0);
            ClipBlit(rp3,(long)4+(breite-i-1)*aufl,11L,rp3,
                (long)4+i*aufl,11L,(long)aufl,hoehe,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp3,(long)4+(breite-i-1)*aufl,11L,
                (long)aufl,hoehe,(long)0xc0);
        }

        if(anzeigen)
            ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);
        update();

        message(win7);

        CloseWindow(win10);
    }

    reverse(win7,12);
    return(1);
}

upside()
 /* this function is flipping (vertikal) the whole picture;
  * remark: the undo-picture gets lost
  */
{
    reverse(win7,13);

    nw9.Screen=scr;
    if((win9=OpenWindow(&nw9))==NULL)
        alert();
    else {
        rp9=win9->RPort;

        for(i=0;i<hoehe/2;i++) {
            ClipBlit(rp1,5L,(long)12+i*3,rp9,0L,0L,
                breite*3*aufl,3L,(long)0xc0);
            ClipBlit(rp1,5L,(long)9+(hoehe-i)*3,rp1,
                5L,(long)12+i*3,breite*3*aufl,3L,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp1,5L,(long)9+(hoehe-i)*3,
                breite*3*aufl,3L,(long)0xc0);

            ClipBlit(rp3,4L,(long)11+i,rp9,0L,0L,
                breite*aufl,1L,(long)0xc0);
            ClipBlit(rp3,4L,(long)10+hoehe-i,rp3,
                4L,(long)11+i,breite*aufl,1L,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp3,4L,(long)10+hoehe-i,
                breite*aufl,1L,(long)0xc0);
        }

        if(anzeigen)
            ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);
        update();

        message(win7);

        CloseWindow(win9);
    }

    update();

    reverse(win7,13);
    return(1);
}

updown(zahl)
 /* this function moves the whole picture the wished number of pixels up;
  * remark: the undo-picture gets lost
  */
    int zahl;
{
    if(zahl>0)
        reverse(win7,13+zahl);
    else
        reverse(win7,16-zahl);

    nw9.Screen=scr;
    if((win9=OpenWindow(&nw9))==NULL)
        alert();
    else {
        rp9=win9->RPort;

        if(zahl>0) {

            ClipBlit(rp3,4L,11L,rp9,0L,0L,
                breite*aufl,(long)zahl,(long)0xc0);
            ClipBlit(rp3,4L,(long)11+zahl,rp3,
                4L,11L,breite*aufl,(long)hoehe-zahl,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp3,4L,(long)11+hoehe-zahl,
                breite*aufl,(long)zahl,(long)0xc0);

            if(anzeigen)
                ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);

            ClipBlit(rp1,5L,12L,rp9,0L,0L,
                breite*3*aufl,(long)zahl*3,(long)0xc0);
            ClipBlit(rp1,5L,(long)12+zahl*3,rp1,
                5L,12L,breite*3*aufl,(long)(hoehe-zahl)*3,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp1,5L,(long)12+(hoehe-zahl)*3,
                breite*3*aufl,(long)zahl*3,(long)0xc0);

        } else {

            ClipBlit(rp3,4L,(long)11+hoehe+zahl,rp9,0L,0L,
                breite*aufl,(long)-zahl,(long)0xc0);
            ClipBlit(rp3,4L,11L,rp3,4L,(long)11-zahl,
                breite*aufl,(long)hoehe+zahl,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp3,4L,11L,
                breite*aufl,(long)-zahl,(long)0xc0);

            if(anzeigen)
                ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);

            ClipBlit(rp1,5L,(long)12+(hoehe+zahl)*3,rp9,0L,0L,
                breite*3*aufl,(long)-zahl*3,(long)0xc0);
            ClipBlit(rp1,5L,12L,rp1,5L,(long)12-zahl*3,
                breite*3*aufl,(long)(hoehe+zahl)*3,(long)0xc0);
            ClipBlit(rp9,0L,0L,rp1,5L,12L,
                breite*3*aufl,(long)-zahl*3,(long)0xc0);

        }

        update();

        CloseWindow(win9);
    }

    if(zahl>0)
        reverse(win7,13+zahl);
    else
        reverse(win7,16-zahl);
}

rightleft(zahl)
 /* this function moves the whole picture the wished number of pixels right;
  * remark: the undo-picture gets lost
  */
    int zahl;
{
    if(zahl>0)
        reverse(win7,19+zahl);
    else
        reverse(win7,22-zahl);

    nw10.Screen=scr;
    if((win10=OpenWindow(&nw10))==NULL)
        alert();
    else {
        rp10=win10->RPort;

        if(zahl>0) {

            ClipBlit(rp3,(long)4+(breite-zahl)*aufl,11L,rp10,0L,0L,
                (long)zahl*aufl,hoehe,(long)0xc0);
            ClipBlit(rp3,4L,11L,rp3,(long)4+(zahl*aufl),11L,
                (long)(breite-zahl)*aufl,hoehe,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp3,4L,11L,
                (long)zahl*aufl,hoehe,(long)0xc0);

            if(anzeigen)
                ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);

            ClipBlit(rp1,(long)5+(breite-zahl)*3*aufl,12L,rp10,0L,0L,
                (long)zahl*3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp1,5L,12L,rp1,(long)5+zahl*3*aufl,12L,
                (long)(breite-zahl)*3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp1,5L,12L,
                (long)zahl*3*aufl,hoehe*3,(long)0xc0);

        } else {

            ClipBlit(rp3,4L,11L,rp10,0L,0L,
                (long)-zahl*aufl,hoehe,(long)0xc0);
            ClipBlit(rp3,(long)4-zahl*aufl,11L,rp3,4L,11L,
                (long)(breite+zahl)*aufl,hoehe,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp3,(long)4+(breite+zahl)*aufl,11L,
                (long)-zahl*aufl,hoehe,(long)0xc0);

            if(anzeigen)
                ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);

            ClipBlit(rp1,5L,12L,rp10,0L,0L,
                (long)-zahl*3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp1,(long)5-zahl*3*aufl,12L,rp1,5L,12L,
                (long)(breite+zahl)*3*aufl,hoehe*3,(long)0xc0);
            ClipBlit(rp10,0L,0L,rp1,(long)5+(breite+zahl)*3*aufl,12L,
                (long)-zahl*3*aufl,hoehe*3,(long)0xc0);

        }

        update();

        CloseWindow(win10);
    }

    if(zahl>0)
        reverse(win7,19+zahl);
    else
        reverse(win7,22-zahl);
}

disk()
 /* in the by this function opened window the user can change the number of
  * bitplanes to be saved as source-code, he can load a palette from an iff-
  * file or even a whole iff-picture or save his painting in the iff-format,
  * moreover he can save his painting as an image-source-code in assembler
  * or c or, if his picture-width is only 16 pixels and he chooses 2 bitpla-
  * nes, as sprite-source-code in assembler or c
  */
{
    reverse(win1,5);
    gad28.NextGadget=(bitmaps==2 && breite==16)?&gad27:NULL;

    nw11.Screen=scr;
    if((win11=OpenWindow(&nw11))==NULL)
        return(0);
    SetPointer(win11,mouseptr,13L,16L,-7L,-6L);
    rp11=win11->RPort;
    SetAPen(rp11,1L);
    rectangle(rp11,66,59,177,105);
    reverse(win11,32+bitmaps);

    do {
        while(no_msg(win11))
            WaitPort(win11->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(class==GADGETUP) {
            id=gad->GadgetID;
            switch(id) {
            case 26:
                save_a_sp();
                break;
            case 27:
                save_c_sp();
                break;
            case 28:
                save_a_im();
                break;
            case 29:
                save_c_im();
                break;
            case 30:
                load_palette();
                break;
            case 31:
                if(!ilbmload()) alert();
                break;
            case 32:
                if(!ilbmsave()) alert();
                break;
            case 33:
            case 34:
            case 35:
            case 36:
                newbmaps(id-32);
                break;
            }
        }
        if(class==VANILLAKEY)
            switch(code) {
            case '1':
            case '2':
            case '3':
            case '4':
                newbmaps(code-'0');
                break;
            case 'p':
                load_palette();
                break;
            case 'l':
                if(!ilbmload()) alert();
                break;
            case 's':
                if(!ilbmsave()) alert();
                break;
            case 'a':
                save_a_im();
                break;
            case 'c':
                save_c_im();
                break;
            case 'q':
                class=CLOSEWINDOW;
                break;
            }
    } while(class!=CLOSEWINDOW);

    class=0;
    CloseWindow(win11);
    reverse(win1,5);
    get_msgs();
    return(1);
}

newbmaps(anz)
 /* this function will be used when the user wants to change the number
  * of bitplanes to be saved; the saving of simplesprites is only possible
  * when you have 2 bitmaps; when the actual width is 16 and the number of
  * bmaps will change from or to 2 this function will also see to hide or
  * get the 'save-as-sprite' - gadgets; the int-variable bitmaps will be set
  */
    int anz;
{
    if(anz!=bitmaps) {

        reverse(win11,32+bitmaps);

        if(breite==16)
            if(bitmaps==2) {
                gad28.NextGadget=NULL;
                SetAPen(rp11,0L);
                RectFill(rp11,69L,83L,174L,103L);
                SetAPen(rp11,1L);
            } else if(anz==2) {
                gad28.NextGadget=&gad27;
                RefreshGList(&gad27,win11,NULL,2L);
            }

        bitmaps=anz;

        reverse(win11,32+bitmaps);
    }
}

load_palette()
 /* this function will ask for a filename and then load and set the color-
  * palette from the wished iff-file; if this iff-file does not contain
  * a cmap-(colormap-)chunk, the user will get informed about this;
  * remark: the extension .ilbm will be added
  */
{
    char ilbm_name[35];
    char id[5];
    long gesamt,length,gelesen;
    int done;
    unsigned char palette[32][3];

    reverse(win11,30);
    id[4]=0;

    if(getname()) {

        strcpy(&ilbm_name,&name);
        strcat(&ilbm_name,".ilbm");
        if((fh=Open(ilbm_name,MODE_OLDFILE))==NULL) {
            abort_info("can't open this file!",30);
            return();
        }

        Read(fh,id,4L);
        if(strcmp("FORM",id)) {
            abort_info("not an iff file!",30);
            return(1);
        }
        Read(fh,&gesamt,4L);

        gelesen=done=0;

        do {
            if(gelesen==gesamt) {
                abort_info("no cmap-chunk!",30);
                Close(fh);
                return();
            } else {
                Read(fh,id,4L);
                Read(fh,&length,4L);
                gelesen+=length+8;

                if(strcmp("CMAP",id))
                    Seek(fh,length,OFFSET_CURRENT);
                else
                    done=1;
            }
        } while(!done);

        Read(fh,palette[0],length);
        for(i=0;i<length/3;i++)
            paletteu[i]=(palette[i][0]<<4)+palette[i][1]+(palette[i][2]>>4);
        LoadRGB4(&scr->ViewPort,paletteu,length/3);

        Close(fh);
    }

    reverse(win11,30);
}

ilbmload()
 /* this function will ask the user for a filename and then load and display
  * the wished picture;
  * remark: the picture can only be loaded when it has the same width,
  *         height and depth as actually set
  * remark: the undo-picture gets lost
  * remark: the extension .ilbm will be added
  */
{
    char ilbm_name[35];
    char id[5];
    struct bmhd {
        UWORD width,height;
        UWORD x,y;
        UBYTE planes;
        UBYTE masking;
        UBYTE compr;
        UBYTE nop;
        UWORD transparent;
        UBYTE xprop,yprop;
        WORD pagewidth,pageheight;
    } bmhd;
    long length;
    unsigned char palette[32][3];
    UWORD col[16];
    long offset;

    reverse(win11,31);
    for(i=0;i<bitmaps;i++)
        bmap.Planes[i]=NULL;
    id[4]=0;

    if(getname()) {

        strcpy(&ilbm_name,&name);
        strcat(&ilbm_name,".ilbm");
        if((fh=Open(ilbm_name,MODE_OLDFILE))==NULL) {
            abort_info("can't open this file!",31);
            return(1);
        }

        Read(fh,id,4L);
        if(strcmp("FORM",id)) {
            abort_info("not an iff file!",31);
            return(1);
        }
        Seek(fh,4L,OFFSET_CURRENT);

        Read(fh,id,4L);
        if(strcmp("ILBM",id)) {
            abort_info("not an ilbm file!",31);
            return(1);
        }

        Read(fh,id,4L);
        if(strcmp("BMHD",id)) {
            abort_info("no bitmap-header!",31);
            return(1);
        }
        Seek(fh,4L,OFFSET_CURRENT);

        Read(fh,&bmhd,20L);
        if(bmhd.width!=breite) {
            abort_info("wrong picture width!",31);
            return(1);
        }
        if(bmhd.height!=hoehe) {
            abort_info("wrong picture height!",31);
            return(1);
        }
        if(bmhd.planes!=bitmaps) {
            abort_info("wrong picture depth!",31);
            return(1);
        }
        if(bmhd.masking!=0) {
            abort_info("wrong masking byte!",31);
            return(1);
        }
        if(bmhd.compr!=0) {
            abort_info("picture data compressed!",31);
            return(1);
        }

        Read(fh,id,4L);
        if(strcmp("CMAP",id)) {
            abort_info("no color-map!",31);
            return(1);
        }
        Read(fh,&length,4L);
        Read(fh,palette[0],length);
        for(i=0;i<16;i++)
            col[i]=(palette[i][0]<<4)+palette[i][1]+(palette[i][2]>>4);

        Read(fh,id,4L);
        if(strcmp("BODY",id)) {
            abort_info("no body-chunk!",31);
            return(1);
        }
        Seek(fh,4L,OFFSET_CURRENT);

        InitBitMap(&bmap,(long)bmhd.planes,
            (long)bmhd.width,(long)bmhd.height);
        for(i=0;i<bmhd.planes;i++)
            if((bmap.Planes[i]=AllocRaster((long)bmhd.width,
                (long)bmhd.height))==NULL) {
                for(j=0;j<i;j++)
                    FreeRaster(bmap.Planes[j],
                        (long)bmhd.width,(long)bmhd.height);
                reverse(win11,31);
                return(0);
            }

        offset=0;
        for(i=bmap.Rows-1;i>=0;i--) {
            for(j=0;j<bitmaps;j++)
                Read(fh,bmap.Planes[j]+offset,(long)bmap.BytesPerRow);
            offset+=bmap.BytesPerRow;
        }

        Close(fh);

        if(length>48) length=48;
        for(i=0;i<length/3;i++)
            paletteu[i]=col[i];
        LoadRGB4(&scr->ViewPort,paletteu,length/3);

        if(aufl==1)
            BltBitMapRastPort(&bmap,0L,0L,rp3,4L,11L,(long)bmhd.width,
                (long)bmhd.height,(long)0xc0);
        else
            for(i=0;i<bmhd.width;i++) {
                BltBitMapRastPort(&bmap,(long)i,0L,rp3,(long)4+i*2,11L,
                    1L,(long)bmhd.height,(long)0xc0);
                BltBitMapRastPort(&bmap,(long)i,0L,rp3,(long)5+i*2,11L,
                    1L,(long)bmhd.height,(long)0xc0);
            }

        for(i=0;i<bmhd.planes;i++)
            FreeRaster(bmap.Planes[i],(long)bmhd.width,(long)bmhd.height);

        if(anzeigen)
            ClipBlit(rp3,4L,11L,rp8,5L,12L,breite*aufl,hoehe,(long)0xc0);
        update();
        erase();
    }

    reverse(win11,31);
    return(1);
}

ilbmsave()
 /* this function will ask the user for a filename and then save the actual
  * picture as an iff-file with the wished name;
  * remark: the extension .ilbm will be added
  */
{
    char ilbm_name[35];
    struct bmhd {
        UWORD width,height;
        UWORD x,y;
        UBYTE planes;
        UBYTE masking;
        UBYTE compr;
        UBYTE nop;
        UWORD transparent;
        UBYTE xprop,yprop;
        WORD pagewidth,pageheight;
    } bmhd;
    char b;
    int w;
    long l,offset;

    reverse(win11,32);
    for(i=0;i<bitmaps;i++)
        bmap.Planes[i]=NULL;

    if(getname()) {
        InitBitMap(&bmap,(long)bitmaps,breite,hoehe);
        for(i=0;i<bitmaps;i++)
            if((bmap.Planes[i]=AllocRaster(breite,hoehe))==NULL) {
                for(j=0;j<i;j++)
                    FreeRaster(bmap.Planes[j],breite,hoehe);
                reverse(win11,32);
                return(0);
            }

        nw12.Screen=scr;
        nw12.BitMap=&bmap;
        if((win12=OpenWindow(&nw12))==NULL) {
            close_ilbm();
            reverse(win11,32);
            return(0);
        }
        rp12=win12->RPort;

        if(aufl==1)
            ClipBlit(rp3,4L,11L,rp12,0L,0L,breite,hoehe,(long)0xc0);
        else
            for(i=0;i<breite;i++)
                ClipBlit(rp3,(long)4+i*2,11L,rp12,(long)i,0L,
                    1L,hoehe,(long)0xc0);

        ClipBlit(rp12,0L,0L,rp12,0L,0L,breite,hoehe,(long)0xc0);

        strcpy(&ilbm_name,&name);
        strcat(&ilbm_name,".ilbm");
        if((fh=Open(ilbm_name,MODE_NEWFILE))==NULL) {
            close_ilbm();
            reverse(win11,32);
            return(0);
        }

        Write(fh,"FORM",4L);
        l=4+28+104+8+bmap.BytesPerRow*bmap.Rows*bmap.Depth;
        Write(fh,&l,4L);
        Write(fh,"ILBM",4L);

        Write(fh,"BMHD",4L);
        l=20;
        Write(fh,&l,4L);

        bmhd.width=breite;
        bmhd.height=hoehe;
        bmhd.x=bmhd.y=0;
        bmhd.planes=bitmaps;
        bmhd.masking=bmhd.compr=bmhd.nop=0;
        bmhd.transparent=0;
        bmhd.xprop=aufl==1?5:10;
        bmhd.yprop=11;
        bmhd.pagewidth=aufl==1?640:320;
        bmhd.pageheight=200;
        Write(fh,&bmhd,20L);

        Write(fh,"CMAP",4L);
        l=96;
        Write(fh,&l,4L);
        for(i=0;i<16;i++) {
            b=((paletteu[i] & 0xf00)>>4);
            Write(fh,&b,1L);
            b=(paletteu[i] & 0x0f0);
            Write(fh,&b,1L);
            b=((paletteu[i] & 0x00f)<<4);
            Write(fh,&b,1L);
        }
        b=0;
        for(i=16;i<32;i++)
            for(j=0;j<3;j++)
                Write(fh,&b,1L);

        Write(fh,"BODY",4L);
        l=bmap.BytesPerRow*bmap.Rows*bmap.Depth;
        Write(fh,&l,4L);

        offset=0;
        for(i=bmap.Rows-1;i>=0;i--) {
            for(j=0;j<bitmaps;j++)
                Write(fh,bmap.Planes[j]+offset,(long)bmap.BytesPerRow);
            offset+=bmap.BytesPerRow;
        }

        close_ilbm();
    }

    reverse(win11,32);
    return(1);
}

close_ilbm()
 /* this function will help to make the function ilbmsave shorter; it is
  * closing everything ilbmsave could have opened and setting the pointer
  * belonging to this things to null
  */
{
    if(fh) Close(fh);
    if(win12) CloseWindow(win12);
    for(i=0;i<bitmaps;i++)
        if(bmap.Planes[i])
            FreeRaster(bmap.Planes[i],breite,hoehe);

    fh=win12=NULL;
}

getname()
 /* this function is needed to ask the user for a file name (to load or
  * save); it opens a window and waits till the user finishes
  */
{
    nw13.Screen=scr;
    if((win13=OpenWindow(&nw13))==NULL) {
        alert();
        return(0);
    }
    SetPointer(win13,mouseptr,13L,16L,-7L,-6L);
    rp13=win13->RPort;
    SetAPen(rp13,1L);

    text(rp13,14,14,"name :");
    ActivateGadget(&gad37,win13,NULL);

    while(no_msg(win13))
        WaitPort(win13->UserPort);

    id=((struct Gadget *)msg->IAddress)->GadgetID;
    ReplyMsg(msg);

    CloseWindow(win13);
    return(id==37 || id==38);
}

abort_info(str,nr)
 /* if any of the disk-functions has to be aborted, it calls this function
  * which displays the reason for aborting and reverses the gadget corres-
  * ponding to the function; at least the file will be closed if it was
  * open; the reason-text and the gadget-id are passed to this function as
  * arguments
  */
    char *str;
    int nr;
{
    nw15.Screen=scr;
    if((win15=OpenWindow(&nw15))==NULL) {
        alert();
        return();
    }
    SetPointer(win15,mouseptr,13L,16L,-7L,-6L);
    rp15=win15->RPort;
    SetAPen(rp15,2L);
    text(rp15,150-strlen(str)*4,15,str);

    WaitPort(win15->UserPort);
    CloseWindow(win15);

    reverse(win11,nr);
    if(fh) Close(fh);
}

compute()
 /* this function is computing the source-code-words to be saved; every
  * of the save-as-source-functions calls this function before saving
  */
{
    for(i=0;i<44;i++)
        for(j=0;j<hoehe;j++)
            for(k=0;k<4;k++)
                src[i][j][k]=0;

    for(i=0;i<hoehe;i++)
        for(j=0;j<bitmaps;j++)
            for(k=0;k<breite;k++)
                if(ReadPixel(rp3,(long)4+k*aufl,(long)11+i)&(1<<j))
                    src[(j*11)+(k>>4)][i][(k>>2)&0x03]|=(1<<(3-(k&0x03)));

    for(i=0;i<44;i++)
        for(j=0;j<hoehe;j++)
            for(k=0;k<4;k++) {
                src[i][j][k]+=48;
                if(src[i][j][k]>57)
                    src[i][j][k]+=39;
            }
}

save_a_im()
 /* this function will ask the user for a filename and then save the picture
  * as assembler-image-source-code with the image-structure;
  * remark: the extension .asm will be added
  */
{
    char asm_name[34],data[4],newline=10;
    static unsigned char number[4][3]={"1st","2nd","3rd","4th"};
    int num,nextline;

    reverse(win11,28);

    if(getname()) {

        strcpy(&asm_name,&name);
        strcat(&asm_name,".asm");
        if((fh=Open(asm_name,MODE_NEWFILE))==NULL) {
            abort_info("can't open this file!",28);
            return();
        }

        compute();

        Write(fh,name,(long)strlen(name));
        Write(fh,"data:",5L);
        Write(fh,&newline,1L);

        nextline=breite>128?8:(breite-1)/16+1;

        for(i=0;i<bitmaps;i++) {
            Write(fh,"; ",2L);
            Write(fh,number[i],3L);
            Write(fh," bitplane:",10L);

            for(j=0;j<hoehe;j++) {
                if(j==0 || num==nextline) {
                    Write(fh,&newline,1L);
                    Write(fh,"        dc.w    $",17L);
                    num=0;
                } else
                    Write(fh,", $",3L);
                num++;
                Write(fh,src[i*11][j],4L);

                for(k=1;k<=11;k++)
                    if(breite>k*16) {
                        if(num==nextline) {
                            Write(fh,&newline,1L);
                            Write(fh,"        dc.w    $",17L);
                            num=0;
                        } else
                            Write(fh,", $",3L);
                        num++;
                        Write(fh,src[i*11+k][j],4L);
                    }

                if(j==hoehe-1) {
                    Write(fh,&newline,1L);
                    if(i==bitmaps-1)
                        Write(fh,&newline,1L);
                }

            }
        }

        Write(fh,name,(long)strlen(name));
        Write(fh,":",1L);
        Write(fh,&newline,1L);
        Write(fh,"; struct Image:",15L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.w 0",14L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.w 0",14L);
        Write(fh,&newline,1L);
        ltoa(breite,data);
        Write(fh,"        dc.w ",13L);
        Write(fh,data,(long)strlen(data));
        Write(fh,&newline,1L);
        ltoa(hoehe,data);
        Write(fh,"        dc.w ",13L);
        Write(fh,data,(long)strlen(data));
        Write(fh,&newline,1L);
        ltoa((long)bitmaps,data);
        Write(fh,"        dc.w ",13L);
        Write(fh,data,(long)strlen(data));
        Write(fh,&newline,1L);
        Write(fh,"        dc.l ",13L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data",4L);
        Write(fh,&newline,1L);
        ltoa((long)(1<<bitmaps)-1,data);
        Write(fh,"        dc.b ",13L);
        Write(fh,data,(long)strlen(data));
        Write(fh,&newline,1L);
        Write(fh,"        dc.b 0",14L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.l 0",14L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Close(fh);
    }

    reverse(win11,28);
}

save_c_im()
 /* this function will ask the user for a filename and then save the picture
  * as c-image-source-code with the image-structure;
  * remark: the extension .c will be added
  */
{
    char c_name[32],data[4],newline=10;
    static unsigned char number[4][3]={"1st","2nd","3rd","4th"};
    int num,nextline;

    reverse(win11,29);

    if(getname()) {

        strcpy(&c_name,&name);
        strcat(&c_name,".c");
        if((fh=Open(c_name,MODE_NEWFILE))==NULL) {
            abort_info("can't open this file!",29);
            return();
        }

        compute();

        Write(fh,"USHORT ",7L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data[] = {",10L);
        Write(fh,&newline,1L);

        nextline=breite>128?8:(breite-1)/16+1;

        for(i=0;i<bitmaps;i++) {
            Write(fh,"         /* ",12L);
            Write(fh,number[i],3L);
            Write(fh," bitplane */",12L);

            for(j=0;j<hoehe;j++) {
                if(j==0 || num==nextline) {
                    if(!(j==hoehe && breite<=(k+1)*16))
                        if(j!=0)
                            Write(fh,",",1L);
                    Write(fh,&newline,1L);
                    Write(fh,"        0x",10L);
                    num=0;
                } else
                    Write(fh,", 0x",4L);
                num++;
                Write(fh,src[i*11][j],4L);

                for(k=1;k<=11;k++)
                    if(breite>k*16) {
                        if(num==nextline) {
                            if(!(j==hoehe-1 && breite<=(k+1)*16))
                                Write(fh,",",1L);
                            Write(fh,&newline,1L);
                            Write(fh,"        0x",10L);
                            num=0;
                        } else
                            Write(fh,", 0x",4L);
                        num++;
                        Write(fh,src[i*11+k][j],4L);
                    }

                if(j==hoehe-1) {
                    if(i==bitmaps-1) {
                        Write(fh," };",3L);
                        Write(fh,&newline,1L);
                    } else
                        Write(fh,",",1L);
                    Write(fh,&newline,1L);
                }

            }
        }

        Write(fh,"struct Image ",13L);
        Write(fh,name,(long)strlen(name));
        Write(fh," =",2L);
        Write(fh,&newline,1L);
        Write(fh,"        { 0, 0, ",16L);
        ltoa(breite,data);
        Write(fh,data,(long)strlen(data));
        Write(fh,", ",2L);
        ltoa(hoehe,data);
        Write(fh,data,(long)strlen(data));
        Write(fh,", ",2L);
        ltoa((long)bitmaps,data);
        Write(fh,data,(long)strlen(data));
        Write(fh,", ",2L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data, ",6L);
        ltoa((long)(1<<bitmaps)-1,data);
        Write(fh,data,(long)strlen(data));
        Write(fh,", 0, NULL };",12L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Close(fh);
    }

    reverse(win11,29);
}

ltoa(nr,s)
 /* this function is turning a long-value to a (ascii-)c-string; i expected
  * to find it the c.lib because it's a standard c function, but i couldn't
  */
    long nr;
    char *s;
{
    int i,sign;

    if((sign=nr)<0)
        nr=-nr;

    i=0;
    do {
        s[i++]=nr%10+'0';
    } while((nr/=10)>0);

    if(sign<0)
        s[i++]='-';

    s[i]=0;

    rev_str(s);
}

rev_str(s)
 /* this function is reversing a c-string; it is used only by ltoa,
  * because ltoa cannot distinguish sides
  */
    char *s;
{
    int i,j;
    char c;

    for(i=0,j=strlen(s)-1;i<j;i++,j--) {
        c=s[i];
        s[i]=s[j];
        s[j]=c;
    }
}

save_a_sp()
 /* this function will ask the user for a filename and then save the picture
  * as assembler-sprite-source-code with the simplesprite-structure;
  * remark: the extension .asm will be added
  */
{
    char asm_name[34],data[4],newline=10;

    reverse(win11,26);

    if(getname()) {

        strcpy(&asm_name,&name);
        strcat(&asm_name,".asm");
        if((fh=Open(asm_name,MODE_NEWFILE))==NULL) {
            abort_info("can't open this file!",26);
            return();
        }

        compute();

        Write(fh,name,(long)strlen(name));
        Write(fh,"data:",5L);
        Write(fh,&newline,1L);

        Write(fh,"        dc.w 0,0",16L);
        Write(fh,&newline,1L);
        for(i=0;i<hoehe;i++) {
            Write(fh,"        dc.w $",14L);
            Write(fh,src[0][i],4L);
            Write(fh,", $",3L);
            Write(fh,src[11][i],4L);
            Write(fh,&newline,1L);
        }
        Write(fh,"        dc.w 0,0",16L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Write(fh,name,(long)strlen(name));
        Write(fh,":",1L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.l ",13L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data",4L);
        Write(fh,&newline,1L);
        ltoa(hoehe,data);
        Write(fh,"        dc.w ",13L);
        Write(fh,data,(long)strlen(data));
        Write(fh,&newline,1L);
        Write(fh,"        dc.w 0",14L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.w 0",14L);
        Write(fh,&newline,1L);
        Write(fh,"        dc.w 0",14L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Close(fh);
    }

    reverse(win11,26);
}

save_c_sp()
 /* this function will ask the user for a filename and then save the picture
  * as c-sprite-source-code with the simplesprite-structure;
  * remark: the extension .c will be added
  */
{
    char c_name[32],data[4],newline=10;

    reverse(win11,27);

    if(getname()) {

        strcpy(&c_name,&name);
        strcat(&c_name,".c");
        if((fh=Open(c_name,MODE_NEWFILE))==NULL) {
            abort_info("can't open this file!",27);
            return();
        }

        compute();

        Write(fh,"UWORD ",6L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data[] = {",10L);
        Write(fh,&newline,1L);

        Write(fh,"        0x0000, 0x0000,",23L);
        Write(fh,&newline,1L);
        for(i=0;i<hoehe;i++) {
            Write(fh,"        0x",10L);
            Write(fh,src[0][i],4L);
            Write(fh,", 0x",4L);
            Write(fh,src[11][i],4L);
            Write(fh,",",1L);
            Write(fh,&newline,1L);
        }
        Write(fh,"        0x0000, 0x0000 };",25L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Write(fh,"struct SimpleSprite ",20L);
        Write(fh,name,(long)strlen(name));
        Write(fh," =",2L);
        Write(fh,&newline,1L);
        Write(fh,"        { ",10L);
        Write(fh,name,(long)strlen(name));
        Write(fh,"data, ",6L);
        ltoa(hoehe,data);
        Write(fh,data,(long)strlen(data));
        Write(fh,", 0, 0, 0 };",12L);
        Write(fh,&newline,1L);
        Write(fh,&newline,1L);

        Close(fh);
    }

    reverse(win11,27);
}

prefs()
 /* in the from this function opened window the user can change between the
  * hires and the normal display mode (where the pixel width is doubled), he
  * can also change the width and the height of the picture
  */
{
    int old_aufl;
    long old_breite,old_hoehe;
    char brei[4],hoe[3];
    int breit,hoeh;

    reverse(win1,7);

    old_aufl=aufl;
    old_breite=breite;
    old_hoehe=hoehe;

    brei[3]=hoe[2]=0;

    prop1.HorizBody=aufl==1?0x018a:0x0315;
    prop1.HorizPot=(USHORT)breite*prop1.HorizBody-1;
    prop2.HorizPot=(USHORT)hoehe*0x0469-1;

    nw16.Screen=scr;
    if((win16=OpenWindow(&nw16))==NULL) {
        reverse(win1,7);
        return(0);
    }

    SetPointer(win16,mouseptr,13L,16L,-7L,-6L);
    rp16=win16->RPort;
    SetAPen(rp16,1L);
    rectangle(rp16,21,75,234,90);
    reverse(win16,42+aufl);

    do {
        while(no_msg(win16))
            WaitPort(win16->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(class==INTUITICKS) {
            breite=prop1.HorizPot/prop1.HorizBody+1;
            hoehe=prop2.HorizPot/prop2.HorizBody+1;

            if(aufl==1)
                breite=breite>166?166:breite;
            else
                breite=breite>83?83:breite;
            hoehe=hoehe>58?58:hoehe;

            ltoa(breite,brei);
            ltoa(hoehe,hoe);

            SetAPen(rp16,0L);
            RectFill(rp16,220L,40L,243L,47L);
            SetAPen(rp16,1L);
            text(rp16,220,40,brei);

            SetAPen(rp16,0L);
            RectFill(rp16,220L,62L,235L,69L);
            SetAPen(rp16,1L);
            text(rp16,220,62,hoe);
        }
        if(class==CLOSEWINDOW) {
            aufl=old_aufl;
            breite=old_breite;
            hoehe=old_hoehe;
        }
        if(class==GADGETUP) {
            id=gad->GadgetID;
            switch(id) {
            case 43:
                if(aufl==2) {
                    aufl=1;
                    reverse(win16,43);
                    reverse(win16,44);
                    breite*=2;

                    prop1.HorizBody=0x018a;
                    prop1.HorizPot=(USHORT)breite*prop1.HorizBody-1;
                    RefreshGList(&gad45,win16,NULL,1L);
                }
                break;
            case 44:
                if(aufl==1) {
                    aufl=2;
                    reverse(win16,43);
                    reverse(win16,44);
                    breite/=2;

                    prop1.HorizBody=0x0315;
                    prop1.HorizPot=(USHORT)breite*prop1.HorizBody-1;
                    RefreshGList(&gad45,win16,NULL,1L);
                }
                break;
            case 47:
                SetAPen(rp1,0L);
                RectFill(rp1,(long)xmin-1,(long)ymin-1,
                    (long)xmax+1,(long)ymax+1);

                SetAPen(rp3,0L);
                RectFill(rp3,4L,11L,
                    (long)3+old_breite*aufl,(long)10+old_hoehe);

                if(anzeigen) {
                    SetAPen(rp8,0L);
                    RectFill(rp8,4L,11L,5+old_breite*old_aufl,12+old_hoehe);
                    breit=breite;
                    hoeh=hoehe;
                    SetAPen(rp8,1L);
                    rectangle(rp8,4,11,5+breit*aufl,12+hoeh);
                }
                xmax=4+breite*3*aufl;
                ymax=11+hoehe*3;

                SetAPen(rp1,1L);
                rectangle(rp1,xmin-1,ymin-1,xmax+1,ymax+1);

                class=CLOSEWINDOW;
                break;
            case 48:
                aufl=old_aufl;
                breite=old_breite;
                hoehe=old_hoehe;
                class=CLOSEWINDOW;
                break;
            }
        }
        if(class==VANILLAKEY)
            if(code=='q') {
                aufl=old_aufl;
                breite=old_breite;
                hoehe=old_hoehe;
                class=CLOSEWINDOW;
            }

    } while(class!=CLOSEWINDOW);

    class=0;
    CloseWindow(win16);
    reverse(win1,7);
    get_msgs();
    return(1);
}

colors()
 /* in the from this function opened window the user can edit the colors;
  * he can then accept his new palette, take the palette before or simple
  * reset the palette to the palette which was at the beginning of the
  * program
  */
{
    UWORD palettes[16];
    char r[2],g[2],b[2];
    USHORT re,gr,bl;
    int col;

    reverse(win1,6);

    for(i=0;i<16;i++)
        palettes[i]=paletteu[i];

    r[1]=g[1]=b[1]=0;

    prop3.HorizPot=((paletteu[colorl]>>8)&0xf)*0x1000+0x0800;
    prop4.HorizPot=((paletteu[colorl]>>4)&0xf)*0x1000+0x0800;
    prop5.HorizPot=(paletteu[colorl]&0xf)*0x1000+0x0800;

    nw17.Screen=scr;
    if((win17=OpenWindow(&nw17))==NULL) {
        reverse(win1,6);
        return(0);
    }

    SetPointer(win17,mouseptr,13L,16L,-7L,-6L);
    rp17=win17->RPort;
    SetAPen(rp17,1L);
    rectangle(rp17,12,15,117,56);

    do {
        while(no_msg(win17))
            WaitPort(win17->UserPort);

        class=msg->Class;
        code=msg->Code;
        gad=(struct Gadget *)msg->IAddress;
        ReplyMsg(msg);

        if(class==INTUITICKS) {
            re=prop3.HorizPot/0x1000;
            gr=prop4.HorizPot/0x1000;
            bl=prop5.HorizPot/0x1000;

            paletteu[colorl]=(re<<8)+(gr<<4)+bl;
            SetRGB4(vp,(long)colorl,(long)re,(long)gr,(long)bl);

            r[0]=re>9?re+'a'-10:re+'0';
            g[0]=gr>9?gr+'a'-10:gr+'0';
            b[0]=bl>9?bl+'a'-10:bl+'0';

            SetAPen(rp17,0L);
            RectFill(rp17,298L,18L,305L,25L);
            SetAPen(rp17,1L);
            text(rp17,298,18,r);

            SetAPen(rp17,0L);
            RectFill(rp17,298L,31L,305L,38L);
            SetAPen(rp17,1L);
            text(rp17,298,31,g);

            SetAPen(rp17,0L);
            RectFill(rp17,298L,44L,305L,51L);
            SetAPen(rp17,1L);
            text(rp17,298,44,b);
        }
        if(class==GADGETUP) { ;
            id=gad->GadgetID;
            switch(id) {
            case 49:
                class=CLOSEWINDOW;
                break;
            case 50:
                for(i=0;i<16;i++)
                    paletteu[i]=palettes[i];
                LoadRGB4(vp,paletteu,16L);
                class=CLOSEWINDOW;
                break;
            case 51:
                for(i=0;i<16;i++)
                    paletteu[i]=paletteb[i];
                LoadRGB4(vp,paletteu,16L);
                class=CLOSEWINDOW;
                break;
            }
        }
        if(class==VANILLAKEY)
            switch(code) {
            case 'b':
                col=(colorl-1)&0xf;
                new_color('l',col);
                prop3.HorizPot=((paletteu[colorl]>>8)&0xf)*0x1000+0x0800;
                prop4.HorizPot=((paletteu[colorl]>>4)&0xf)*0x1000+0x0800;
                prop5.HorizPot=(paletteu[colorl]&0xf)*0x1000+0x0800;
                RefreshGList(&gad54,win17,NULL,3L);
                break;
            case 'n':
                col=(colorl+1)&0xf;
                new_color('l',col);
                prop3.HorizPot=((paletteu[colorl]>>8)&0xf)*0x1000+0x0800;
                prop4.HorizPot=((paletteu[colorl]>>4)&0xf)*0x1000+0x0800;
                prop5.HorizPot=(paletteu[colorl]&0xf)*0x1000+0x0800;
                RefreshGList(&gad54,win17,NULL,3L);
                break;
            case 'q':
                class=CLOSEWINDOW;
                break;
            }

    } while(class!=CLOSEWINDOW);

    class=0;
    CloseWindow(win17);
    reverse(win1,6);
    get_msgs();
    return(1);
}
