/*
        Flame

        A demo of rtg.library

        Written by Thomas & Hans-Jörg Frieden
                   Schlossstr. 176
                   54293 Trier
                   tfrieden@fax.uni-trier.de
                   hfrieden@fix.uni-trier.de

*/
//* "Includes"
#include <stdlib.h>
#include <proto/utility.h>
#include <proto/exec.h>
#include <clib/rtgmaster_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <pragmas/rtgmaster_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <exec/memory.h>
#include <utility/tagitem.h>
#include <rtgmaster/rtgmaster.h>
#include <rtgmaster/rtgsublibs.h>
#include <rtgmaster/rtgc2p.h>
#include <proto/rtgmaster.h>
#include "timer.h"
#include <string.h>
#include <stdio.h>

int currentbuffer=0;

//*

//* "Defines"
#define XSIZE 80
#define YSIZE 65
#define YSCRN 60
#define MSIZE (XSIZE*YSIZE)
#define DECAY 3
#define CBUF    76800
//*
//* "Pragmas"
extern void __asm CopyFrame(register __a0 UBYTE *adr, 
                            register __d0 ULONG size);
extern void __asm CopyFrame2(register __a0 UBYTE *adr, 
                             register __d0 ULONG aize);
extern void __asm DrawMeter(register __a0 APTR buf, 
                            register __d0 ULONG fps);

UBYTE MouseButton(void);
//*
//* "Globals"
struct RtgScreen *RtgScreen;
struct ScreenReq *sr;
struct RTGMasterBase *RTGMasterBase;
struct Library *UtilityBase;
struct TagItem rtag[] = {
    smr_MinWidth,       320,
    smr_MinHeight,      200,
    smr_MaxWidth,       1024,
    smr_MaxHeight,      768,
    smr_ChunkySupport,  512,
    smr_PlanarSupport,  -1,
    smr_Buffers,2,
    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,
    TAG_DONE,           0
};

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

UBYTE *sc1;
UBYTE scrn[MSIZE];
ULONG cmap[800];
UBYTE blah;
BOOL Planar;
UBYTE *cbuf=NULL;
ULONG width;
ULONG height;
UBYTE *sadr;
ULONG num,avg;
ULONG c2psignal;
//*
//* "NewFrame"
void NewFrame(void) {
    int i,x;
    UBYTE *a;

    extern void GenFrame(void);

    a=&scrn[MSIZE-1]; i=XSIZE;

    while (i>0) {
        x=rand();
        if (x>RAND_MAX/2) *a=255;
        else *a=0;
        i--; a--;
    }

    i=MSIZE-XSIZE-1;
    a=scrn;

    GenFrame();
}
//*
//* "DrawFrame"
void DrawFrame(struct RtgScreen *s, ULONG size, ULONG ticks) {

    if (blah==0) CopyFrame(cbuf, size);
    else CopyFrame2(cbuf,size);
    DrawMeter(cbuf, ticks);  
    CopyRtgBlit(RtgScreen,sadr,cbuf,0,0,0,width,height,width,height,0,0);
}
//*
//* "DrawFrameP"
void DrawFrameP(struct RtgScreen *s, ULONG size, ULONG ticks) {
    UBYTE *adr;

    adr=cbuf;                               // Draw into chunky buffer first
    if (blah==0) CopyFrame(adr, 320);
    else CopyFrame2(adr,320);
    DrawMeter(adr, ticks);
    adr = sadr;
    if (tacks[1].ti_Data==512) CopyRtgBlit(RtgScreen,sadr,cbuf,0,0,0,width,height,width,height,0,0);
    // No Doublebuffering, if on Workbench Window
    else
    {
     // For Kalms-c2p we have to use Doublebuffering
     CopyRtgBlit(RtgScreen,GetBufAdr(RtgScreen,1-currentbuffer),cbuf,0,0,0,width,height,width,height,0,0);
     SwitchScreens(RtgScreen,1-currentbuffer);
     currentbuffer=1-currentbuffer;
    }
}
//*
//* "fail"
void fail(void) {
    if (RtgScreen) CloseRtgScreen(RtgScreen);
    if (RTGMasterBase) CloseLibrary((struct Library *)RTGMasterBase);
    if (UtilityBase) CloseLibrary(UtilityBase);
    if (cbuf) FreeMem(cbuf, CBUF);
    exit(0L);
}
//*
//* "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 size;
    ULONG ticks=0, max=0, min=300;

    if (argc>1 && stricmp(argv[1],"small")==0) blah=1; else blah=0;
    if (argc>2 && stricmp(argv[2],"window")==0) tacks[1].ti_Data=LUT8;
    if (argc>1 && stricmp(argv[1],"window")==0) tacks[1].ti_Data=LUT8;
        if (InitTimer()==FALSE) {
        printf("Unable to open timer device\n");
        fail();
    }

    RTGMasterBase = (struct RTGMasterBase *)OpenLibrary((STRPTR)"rtgmaster.library", 0);
    UtilityBase = OpenLibrary((STRPTR)"utility.library", 37L);
    c2psignal=AllocSignal(-1);
    sr = RtgScreenModeReq(rtag);

    if (sr==NULL) fail();
    if (c2psignal==-1) 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_Height,gtag);
    height = 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();
    }

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

    printf("Screen is %ld x %ld x %ld\n", gtag[1].ti_Data, gtag[2].ti_Data, gtag[3].ti_Data);
    printf("It has %ld bytes per row", size);
    if (size>gtag[1].ti_Data) {
        printf(", which means that the screen is wider than what you see\n");
    } else printf("\n");

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

if (gtag[3].ti_Data==8)
{
    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;
}
else
{
   cmap[0] = 64 * 65536;
    rr = 0;
    rg = 0;
    rb = 0;
    x = 1;
    for (i = 0; i < 16; i++) {
        cmap[x++] = rr * 0x1111111;
        cmap[x++] = rg * 0x1111111;
        cmap[x++] = rb * 0x1111111;
        rr += 12;
    }
    for (i = 0; i < 31; i++) {
        cmap[x++] = rr * 0x1111111;
        cmap[x++] = rg * 0x1111111;
        cmap[x++] = rb * 0x1111111;
        rg += 12;
    }
    for (i = 0; i < 12; i++) {
        cmap[x++] = rr * 0x1111111;
        cmap[x++] = rg * 0x1111111;
        cmap[x++] = rb * 0x1111111;
        rb += 12;
    }
    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);

        num=0;
        while(MouseButton()==0) {
            StartClock();
            NewFrame();
            if (Planar==FALSE) DrawFrame(RtgScreen, size, ticks);
            else DrawFrameP(RtgScreen, size, ticks);
            ticks=StopClock();
            num++;
            avg+=ticks;
            if (max<ticks) max=ticks;
            if (min>ticks) min=ticks;
        }
        UnlockRtgScreen(RtgScreen);
        CloseRtgScreen(RtgScreen);
    }
    if (max==0) max=1;
    if (min==0) min=1;
    printf("Min Frame rate: %ld\n", max);
    printf("Max Frame rate: %ld\n", min);
    printf("Avg Frame rate: %ld\n", avg/num);
    CloseTimer();
    FreeSignal(c2psignal);
    FreeMem(cbuf,CBUF);
    FreeRtgScreenModeReq(sr);
    CloseLibrary((struct Library *)RTGMasterBase);
    CloseLibrary(UtilityBase);
}
//*

