
/* Includes here */

/// "Includes"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <proto/reqtools.h>
#include <proto/iffparse.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <iffp/ilbmapp.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <intuition/intuition.h>
#include <libraries/reqtools.h>
///

/* Declarations here */

/// "Declarations"
char *Version = "$VER: MiniMand 1.0 (12 Apr 1995)";

extern struct ExecBase  *SysBase;
struct IntuitionBase    *IntuitionBase;
struct Library          *IFFParseBase;
struct ReqToolsBase     *ReqToolsBase;

struct ILBMInfo ilbm = {0};

struct Window           *mywindow = NULL;
struct Screen           *myscreen = NULL;

struct TagItem WindowTags[] =
{
        WA_Left,     0,
        WA_Top,      0,
        WA_Width,    NULL,
        WA_Height,   NULL,
        WA_IDCMP,    VANILLAKEY | IDCMP_MOUSEBUTTONS,
        WA_Flags,    WFLG_SMART_REFRESH | WFLG_BORDERLESS |
                     WFLG_BACKDROP | WFLG_ACTIVATE,
        WA_CustomScreen, NULL,
        TAG_DONE
};

struct TagItem ScreenTags[] =
{
        SA_Depth, 4,
        SA_Type, CUSTOMSCREEN,
        SA_ShowTitle, FALSE,
        SA_Title, (ULONG)"MiniMand 1.0",
        SA_Colors, NULL,
        SA_Behind, NULL,
        SA_DisplayID, DEFAULT_MONITOR_ID,
        SA_Quiet, TRUE,
        SA_Interleaved, TRUE,
        TAG_DONE
};

struct RDArgs *RDArgs;

struct
{
        char *xmin;
        char *xmax;
        char *ymin;
        char *ymax;
        long quiet;
        long julia;
        char *jreal;
        char *jimag;
        long hires;
        long lace;
        int *planes;
        int *scrx;
        int *scry;
        int *iter;
        char *save;
        int *palette;
        int *batch;
} Arguments;

struct
{
        float xmin;
        float xmax;
        float ymin;
        float ymax;
        int julia;
        float jreal;
        float jimag;
        int scrx;
        int scry;
        int maxiter;
        int cols;
} Vars;

struct IntuiMessage *mymessage;
BOOL terminated = FALSE;
clock_t start, end;
int XMouse1, YMouse1, XMouse2, YMouse2;

///

/* Functions declared here */

void OpenLibs(void);
void Cleanup(int, STRPTR);
void Checkmsg(struct IntuiMessage *mymessage);
void make_mand(void);
void make_julia(void);
void FixArgs(void);

/* Main function here */

void main(int argc, char *argv[])
/// "Main"
{
int i;

Vars.xmin = -2;
Vars.xmax = 2;
Vars.ymin = -2;
Vars.ymax = 2;
Vars.julia = FALSE;
Vars.jreal = -2;
Vars.jimag = 2;
Vars.scrx = 320;
Vars.scry = 256;
Vars.maxiter = 16;
Vars.cols = 16;

if(RDArgs = ReadArgs("REMIN/K,REMAX/K,IMIN/K,IMAX/K,QUIET/S,JULIA/S,JREAL/K,JIMAG/K,HIRES/S,LACE/S,PLANES/K/N,SCRX/K/N,SCRY/K/N,ITER/K/N,SAVE/K,PALETTE/S,BATCH/S", (long *) &Arguments, NULL))
    FixArgs();

OpenLibs();

if(SysBase->AttnFlags & AFF_68881)

myscreen = OpenScreenTagList(NULL, ScreenTags);

if (!myscreen)
    Cleanup(10, "Unable to open screen");

WindowTags[2].ti_Data = (ULONG)Vars.scrx;
WindowTags[3].ti_Data = (ULONG)Vars.scry;
WindowTags[6].ti_Data = (ULONG)myscreen;

mywindow = OpenWindowTagList(NULL, WindowTags);

if (!mywindow)
    Cleanup(10, "Unable to open window");

if(Arguments.palette)
    i=rtPaletteRequest("Choose colors", NULL, RT_Screen, myscreen);
if(!Arguments.palette || i == -1)
    for(i = 0; i < Vars.cols; i++)
        SetRGB32(&myscreen->ViewPort, i, (i*255 / (Vars.cols-1)) << 24, 0, (i*255 / (Vars.cols-1)) << 24);
if (Vars.julia)
        make_julia();
else
        make_mand();
if (!Arguments.batch)
while(!terminated)
{
        Wait( 1 << mywindow->UserPort->mp_SigBit);
        while( mymessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort))
                Checkmsg(mymessage);
}

if(Arguments.save)
    screensave(&ilbm, myscreen, NULL, NULL, Arguments.save);  

printf("Approx time used = %d s\n",(end - start)/CLOCKS_PER_SEC);
Cleanup(0, NULL);

}
///

/* Functions here */

void OpenLibs(void)
/// "OpenLibs"
{
if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",36L)))
    Cleanup(10, "Unable to open intuition.library v36 or higher");
if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)))
    Cleanup(10, "Unable to open graphics.library");
if (!(ReqToolsBase = (struct ReqToolsBase *)OpenLibrary("reqtools.library",0L)))
    Cleanup(10, "Unable to open reqtools.library");
if (!(IFFParseBase = OpenLibrary("iffparse.library",0L)))
    Cleanup(10, "Unable to open iffparse.library");
if(!(ilbm.ParseInfo.iff = AllocIFF()))
    Cleanup(10, "Unable to allocate IFF");
}
///

void Cleanup(int return_code, STRPTR return_text)
/// "Cleanup"
{
if (return_code)
        printf("%d: %s\n", return_code, return_text);

if (ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);

if (mywindow) CloseWindow(mywindow);

if (myscreen) CloseScreen(myscreen);

if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);

if (GfxBase) CloseLibrary ((struct Library *)GfxBase);

if (IFFParseBase) CloseLibrary(IFFParseBase);

if (ReqToolsBase) CloseLibrary((struct Library *)ReqToolsBase);

exit(NULL);
}
///

void Checkmsg(struct IntuiMessage *mymessage)
/// "Checkmsg"
{
float xdif = Vars.xmax - Vars.xmin, ydif = Vars.ymax - Vars.ymin;

ReplyMsg((struct Message *)mymessage);

switch(mymessage->Class) {
    case VANILLAKEY:
    if(mymessage->Code == 0x1B)
        terminated=TRUE;
        break;
    case IDCMP_MOUSEBUTTONS:
        if(mymessage->Code == SELECTDOWN) {
            XMouse1 = mymessage->MouseX;
            YMouse1 = mymessage->MouseY;
            // printf("Ned X = %d Y = %d\n",XMouse1,YMouse1);
            }
        if(mymessage->Code == SELECTUP) {
            XMouse2 = mymessage->MouseX;
            YMouse2 = mymessage->MouseY;
            // printf("Upp X = %d Y = %d\n",XMouse2,YMouse2);
            Vars.xmax = xdif * MAX(XMouse1,XMouse2) / Vars.scrx + Vars.xmin;
            Vars.xmin = xdif * MIN(XMouse1,XMouse2) / Vars.scrx + Vars.xmin;
            Vars.ymax = ydif * MAX(YMouse1,YMouse2) / Vars.scry + Vars.ymin;
            Vars.ymin = ydif * MIN(YMouse1,YMouse2) / Vars.scry + Vars.ymin;
            printf("REMAX = %f, REMIN = %f, IMAX = %f, IMIN = %f\n\n",Vars.xmax, Vars.xmin, Vars.ymax, Vars.ymin);
            if(Vars.julia)
                make_julia();
            else
                make_mand();
            }
        break;
        }
}
///

void make_mand(void)
/// "make_mand"
{
register int n, sx, sy;
float x, y, t, zr, zi;
float xdif, ydif, ystep, xstep;

xdif = Vars.xmax-Vars.xmin;
ydif = Vars.ymax-Vars.ymin;
ystep = (ydif)/Vars.scry;
xstep = (xdif)/Vars.scrx;

start = clock();
for(sy = 0, y=Vars.ymin; sy < Vars.scry; sy++)
{               
        for(sx = 0, x=Vars.xmin; sx < Vars.scrx; sx++)
        {
                zr=x;
                zi=y;
                for(n=1; (zr*zr+zi*zi < 4) && (n<Vars.maxiter); n++)
                {
                        t=zr*zr-zi*zi+x;
                        zi=zr*zi*2+y;
                        zr=t;
                }
                SetAPen(mywindow->RPort, n * Vars.cols / Vars.maxiter);
                WritePixel(mywindow->RPort, sx, sy);
                if(mymessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort))
                        Checkmsg(mymessage);
                x+=xstep;
        }
        if(terminated==TRUE)
                Cleanup(0, NULL);
        y+=ystep;
}
end = clock();
}
///

void make_julia(void)
/// "make_julia"
{
register int n, sx, sy;
float x, y, t, zr, zi;
float xdif, ydif, ystep, xstep;
float ci = Vars.jimag, cr = Vars.jreal;

xdif = Vars.xmax-Vars.xmin;
ydif = Vars.ymax-Vars.ymin;
ystep = (ydif)/Vars.scry;
xstep = (xdif)/Vars.scrx;

start = clock();
for(sy = 0, y=Vars.ymin; sy < Vars.scry; sy++)
{               
        for(sx = 0, x=Vars.xmin; sx < Vars.scrx; sx++)
        {
                zr=x;
                zi=y;
                for(n=1; (zr*zr+zi*zi < 4) && (n<Vars.maxiter); n++)
                {
                        t=zr*zr-zi*zi+ci;
                        zi=zr*zi*2+cr;
                        zr=t;
                }
                SetAPen(mywindow->RPort, n * Vars.cols / Vars.maxiter);
                WritePixel(mywindow->RPort, sx, sy);
                if(mymessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort))
                        Checkmsg(mymessage);
                x+=xstep;
        }
        if(terminated==TRUE)
                Cleanup(0, NULL);
        y+=ystep;
}
end = clock();
}
///

void FixArgs(void)
/// "FixArgs"
{
if(Arguments.xmin)
        Vars.xmin=atof(Arguments.xmin);
if(Arguments.xmax)
        Vars.xmax=atof(Arguments.xmax);
if(Arguments.ymin)
        Vars.ymax=-atof(Arguments.ymin);
if(Arguments.ymax)
        Vars.ymin=-atof(Arguments.ymax);
if(Arguments.quiet || Arguments.batch)
{
        ScreenTags[5].ti_Data = TRUE;
        WindowTags[5].ti_Data ^= WFLG_ACTIVATE;
}
if(Arguments.julia)
{
        Vars.julia = TRUE;
        if(Arguments.jreal)
                Vars.jreal=atof(Arguments.jreal);
        if(Arguments.jimag)
                Vars.jimag=atof(Arguments.jimag);
}
if(Arguments.hires && Arguments.lace)
{
        ScreenTags[6].ti_Data |= HIRESLACE_KEY;
        Vars.scrx=640;
        Vars.scry=512;
}
else
{
        if(Arguments.hires)
        {
                ScreenTags[6].ti_Data |= HIRES_KEY;
                Vars.scrx=640;
        }
        if(Arguments.lace)
        {
                ScreenTags[6].ti_Data |= LORESLACE_KEY;
                Vars.scry=512;
        }
}
if(Arguments.planes)
{
    ScreenTags[0].ti_Data = *Arguments.planes;
    Vars.cols = 1 << *Arguments.planes;
}
if(Arguments.scrx)
        Vars.scrx=*Arguments.scrx;
if(Arguments.scry)
        Vars.scry=*Arguments.scry;
if(Arguments.iter)
        Vars.maxiter=*Arguments.iter;
}
///
