/*

	RTG Library Usage Demo - MandelBrot Generator

*/
//* "Includes"


/* Generic "Include Everything"-type file */
#include <global.h>
#include <math.h>



//*
//* "Globals"
struct RtgScreen *RtgScreen;
struct ScreenReq *sr;
struct RTGMasterBase *RTGMasterBase;
struct Library *UtilityBase, *IntuitionBase;
struct Library *GfxBase;
struct TagItem rtag[] = {
    smr_ChunkySupport,  -1,
    smr_PlanarSupport,  -1,
    smr_PrefsFileName,  (Tag)"MandelRTG.prefs",
    TAG_DONE,           NULL
};

struct TagItem gtag[] = {
    grd_BytesPerRow,    0,
    grd_Width,          0,
    grd_Height,         0,
    grd_Depth,          0,
    grd_PixelLayout,    0,
    grd_ColorSpace,     0,
    grd_PlaneSize,      0,
    grd_BusSystem,      0,
    TAG_DONE,           0
};

struct TagItem tacks[] = {
    TAG_DONE,0
};

BOOL Planar;
UBYTE *cbuf=NULL;
ULONG width;
UBYTE *sadr;
ULONG cmap[800];
ULONG size;
#define CBUF 76800


typedef struct {
    float x,y;
} complex;


const MAX=256;

/*
 * This is done using an ugly direct hardware hit
 * Should be an input handler or similar in future versions/real-life
 * applications!
 */
extern int MouseButton(void);

//*
//* "fail"
void fail(void) {
    if (RtgScreen) CloseRtgScreen(RtgScreen);
    if (RTGMasterBase) CloseLibrary((struct Library *)RTGMasterBase);
    if (UtilityBase) CloseLibrary(UtilityBase);
    if (cbuf) FreeVec(cbuf);
    exit(0L);
}
//*
//* "Iterate"
int iterate(complex zInit) {
    complex z;
    float a,b;
    int cnt;

    z=zInit;
    cnt=0;
    while ((z.x*z.x+z.y*z.y<=4.0) && (cnt<MAX)) {
	a=z.x*z.x-z.y*z.y;
	b=2*z.x*z.y;
	z.x=a; z.y=b;
	z.x+=zInit.x;
	z.y+=zInit.y;
	cnt++;
    }
    return cnt;
}
//*
//* "Mandelbrot"
void Mandelbrot(float rMin, float rMax, float iMin, float iMax,
    int cols, int rows) {
    float rInc, iInc;
    int x,y,count;
    complex zInit;

    rInc=(rMax-rMin)/(float)cols;
    iInc=(iMax-iMin)/(float)rows;
    zInit.x=rMin;
    for (x=0; x<cols; x++) {
	zInit.y=iMin;
	for (y=0; y<cols; y++) {
	    count=iterate(zInit);
	    WriteRtgPixel(RtgScreen,sadr,x,y,count);
	    zInit.y+=iInc;
	    if (MouseButton()) return;
	}
	zInit.x+=rInc;
    }
}
//*
//* "main"
void main(int argc, char *argv[]) {
   /*
    * Since this is a demo, I don't check anything at all
    * and simply assume that every open went ok... 8-)
    */
    int i,x;
    struct TagItem *tag;
    UBYTE rr, rg, rb;
    ULONG width, height;
    float iMin, iMax, rMin, rMax;
    rMin=-2.25; rMax=0.75;
    iMin=-1.25; iMax=1.25;

    if (argc>1) rMin=atof(argv[1]);
    if (argc>2) rMax=atof(argv[2]);
    if (argc>3) iMin=atof(argv[3]);
    if (argc>4) iMax=atof(argv[4]);


    RTGMasterBase = (struct RTGMasterBase *)OpenLibrary((STRPTR)"rtgmaster.library", 0);
    UtilityBase = OpenLibrary((STRPTR)"utility.library", 37L);
    IntuitionBase = OpenLibrary("intuition.library", 37L);
    GfxBase = OpenLibrary("graphics.library", 37L);

    sr = RtgScreenModeReq(rtag);

    if (sr==NULL) fail();

    RtgScreen = OpenRtgScreen(sr, tacks);

    GetRtgScreenData(RtgScreen, gtag);

    tag=FindTagItem(grd_BytesPerRow, gtag);
    size = tag->ti_Data;

    tag=FindTagItem(grd_Width, gtag);
    width = tag->ti_Data;

    tag=FindTagItem(grd_PixelLayout, gtag);
    if (tag->ti_Data != grd_PLANAR && tag->ti_Data != grd_CHUNKY) {
	printf("Screenmode not supported\n");
	fail();
    }

    printf("Screen pixel layout is ");
    switch(tag->ti_Data) {
	case grd_PLANAR:        printf("planar\n"); break;
	case grd_PLANATI:       printf("interleaved planar\n"); break;
	case grd_CHUNKY:        printf("8-Bit Z-Ordered (chunky)\n"); break;
	case grd_HICOL15:       printf("15-Bit Chunky (2 Byte/pixel)\n"); break;
	case grd_HICOL16:       printf("16-Bit Chunky (2 Byte/pixel)\n"); break;
	case grd_TRUECOL24:     printf("24-Bit Chunky (3 Byte/pixel)\n"); break;
	case grd_TRUECOL24P:    printf("24-Bit Chunky (3 Byteplanes/pixel)\n"); break;
	case grd_TRUECOL32:     printf("24-Bit Chunky (4 Bytes/pixel)\n"); break;
	case grd_GRAFFITI:      printf("Graffiti 8 bit\n"); break;
	case grd_TRUECOL32B:    printf("24-Bit Chunky (4 Bytes/pixel)\n"); break;
	default:                printf("unknown (%d)\n", tag->ti_Data); break;
    }

    tag=FindTagItem(grd_ColorSpace, gtag);
    if (tag->ti_Data) {
	printf("Color space is ");
	switch(tag->ti_Data) {
	    case grd_Palette:   printf("CLUT-Based\n"); break;
	    case grd_RGB:       printf("RGB (low-endian RGB)\n"); break;
	    case grd_BGR:       printf("BGR (high-endian RGB)\n"); break;
	    default:            printf("unknown (%d)\n", tag->ti_Data); break;
	}
    }

    tag=FindTagItem(grd_BusSystem, gtag);
    if (tag->ti_Data) {
	printf("Graphics card bus is ");
	switch(tag->ti_Data) {
	    case grd_Z3:        printf("Zorro III\n"); break;
	    case grd_Z2:        printf("Zorro II\n"); break;
	    case grd_Custom:    printf("default custom chips\n"); break;
	    case grd_RGBPort:   printf("conneted to the RGB Port\n"); break;
	    case grd_GVP:       printf("GVP Special Bus (EGS110)\n"); break;
	    case grd_DDirect:   printf("DracCoŽ Direct\n"); break;
	    default:            printf("an unknown bus system\n"); break;
	}
    }

    if (tag->ti_Data == grd_PLANAR) Planar = TRUE;
    else Planar = FALSE;

    tag=FindTagItem(grd_Width, gtag);
    if (tag) width=tag->ti_Data;
    tag=FindTagItem(grd_Height, gtag);
    if (tag) height=tag->ti_Data;

    printf("Screen is %ld x %ld x %ld\n", width, height, gtag[3].ti_Data);
    printf("It has %ld bytes per row\n", size);


    if (Planar == TRUE) {
	cbuf = AllocVec(CBUF, MEMF_CLEAR|MEMF_FAST);
	if (cbuf==NULL) {
	    cbuf=AllocVec(CBUF, MEMF_CLEAR);
	    if (cbuf==NULL) {
		printf("Out of memory *SIGH*\n");
		fail();
	    }
	}
    }

    cmap[0] = 256 * 65536;
    rr = 0;
    rg = 0;
    rb = 0;
    x = 1;
    for (i = 0; i < 64; i++) {
	cmap[x++] = rr * 0x1111111;
	cmap[x++] = rg * 0x1111111;
	cmap[x++] = rb * 0x1111111;
	rr += 3;
    }
    for (i = 0; i < 127; i++) {
	cmap[x++] = rr * 0x1111111;
	cmap[x++] = rg * 0x1111111;
	cmap[x++] = rb * 0x1111111;
	rg += 3;
    }
    for (i = 0; i < 60; i++) {
	cmap[x++] = rr * 0x1111111;
	cmap[x++] = rg * 0x1111111;
	cmap[x++] = rb * 0x1111111;
	rb += 3;
    }
    for (i = 0; i < 4; i++) {
	cmap[x++]=0xFFFFFFFF;
	cmap[x++]=0xFFFFFFFF;
	cmap[x++]=0xFFFFFFFF;
    }
    cmap[x]=0;
    LockRtgScreen(RtgScreen);
    LoadRGBRtg(RtgScreen, (APTR) cmap);
    UnlockRtgScreen(RtgScreen);

    if (RtgScreen) {
	LockRtgScreen(RtgScreen);
	sadr = (UBYTE *)GetBufAdr(RtgScreen,0);

	//Mandelbrot(-1.08816, -0.93391, 0.36621, 0.25723, width, height);
	Mandelbrot(rMin, rMax, iMin, iMax, width, height);
	while (MouseButton()==0);
	UnlockRtgScreen(RtgScreen);
	CloseRtgScreen(RtgScreen);
    }

    CloseLibrary(GfxBase);
    CloseLibrary((struct Library *)RTGMasterBase);
    CloseLibrary(UtilityBase);
    CloseLibrary(IntuitionBase);
}
//*

