#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <exec/memory.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <utility/hooks.h>

#include "graffiti.h"

#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/timer.h>

void __regargs __chkabort (void);
void __regargs __chkabort (void)
{
}

extern WORD fastsin (WORD, WORD);
extern WORD fastcos (WORD, WORD);

struct Library * TimerBase;
struct timerequest * TimerIO;

int _STI_205_Timer (void)
{
    if (!(TimerIO = AllocMem (sizeof (struct timerequest), MEMF_PUBLIC|MEMF_CLEAR)) )
	return 1;

    if (OpenDevice (TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0))
    {
	FreeMem (TimerIO, sizeof (struct timerequest));
	return 1;
    }

    TimerBase = (struct Library *)TimerIO->tr_node.io_Device;

    return 0;
}

void _STD_205_Device (void)
{
    CloseDevice ((struct IORequest *)TimerIO);
}

#define DEMO_GENELLIPSE     0
#define DEMO_ROTATELINE     0
#define DEMO_ROTATEBOX	    1

int main (int argc, char ** argv)
{
    struct GraffitiHandle * gh;
    struct IntuiMessage * im;
    ULONG width;
    int mode, fps;
    struct timeval time1, time2;
    char string[32];
    int frame, sec, white;

#if DEMO_GENELLIPSE
    int x, y, rx, ry, angle, col;
#endif
#if DEMO_ROTATELINE
    int x, y, x1, y1, x2, y2, angle;
#endif
#if DEMO_ROTATEBOX
    int x, y, x1, y1, x2, y2, x3, y3, angle;
#endif

    /* Init card */
    if (argc == 1)
    {
	gh = Graffiti_Init (
	    GTI_BUFFER, GRAFFITI_BUFFER_DOUBLE,
	    TAG_END);
    }
    else
    {
	mode = atoi (argv[1]);

	if (mode < 0 || mode > 1)
	{
	    fprintf (stderr, "Mode must be between 0 or 1\n");
	    return 10;
	}

	gh = Graffiti_Init (
	    GTI_RESOLUTION, mode ? GRAFFITI_RES_640 : GRAFFITI_RES_320,
	    GTI_BUFFER, GRAFFITI_BUFFER_DOUBLE,
	    TAG_END);
    }

    Graffiti_InstallPalette3 (gh);

    Graffiti_GetAttr (gh, GTI_WIDTH, &width);

    frame = 0;

    white = Graffiti_FindBestMatch (gh, 255,255,255);

#if DEMO_GENELLIPSE
    x = width/2;
    y = 128;
    angle = 0;
    col = 160;
    rx = 80;
    ry = 20;
#endif
#if DEMO_ROTATELINE
    x = width/2;
    y = 128;
    angle = 0;
    x1 = 100;
    y1 = 0;
    Graffiti_SetFG (gh, white);
#endif
#if DEMO_ROTATEBOX
    x = width/2;
    y = 128;
    angle = 0;
    x1 = 100;
    y1 = 0;
    Graffiti_SetFG (gh, white);
#endif

    sec = 0;
    fps = 0;

    GetSysTime (&time1);

    for (;;)
    {
	if ((im = Graffiti_CheckEvent (gh)))
	{
	    ReplyMsg ((struct Message *)im);
	    break;
	}

	Graffiti_UseNextBuffer (gh);

#if DEMO_GENELLIPSE
	/* about 16fps */
	Graffiti_SetFG (gh, col);
	Graffiti_FillGenEllipse (gh, x, y, rx, ry, angle);
	angle += 128;
	col ++;
#endif

#if DEMO_ROTATELINE
	/* about 24fps */
	x2 = fastcos (angle, x1);
	y2 = fastsin (angle, x1);

	/* printf ("vec=%d/%d\n", x2, y2); */

	Graffiti_DrawLine (gh, x-x2,y-y2, x+x2,y+y2);
	Graffiti_DrawLine (gh, x-y2,y+x2, x+y2,y-x2);

	angle += 128;
#endif

#if DEMO_ROTATEBOX
	/* about 24fps */
	x2 = fastcos (angle, x1);
	y2 = fastsin (angle, x1);
	x3 = y2;
	y3 = -x2;

	/* printf ("vec=%d/%d\n", x2, y2); */

	Graffiti_DrawLine (gh, x+x2,y+y2, x+x3,y+y3);
	Graffiti_DrawLine (gh, x+x3,y+y3, x-x2,y-y2);
	Graffiti_DrawLine (gh, x-x2,y-y2, x-x3,y-y3);
	Graffiti_DrawLine (gh, x-x3,y-y3, x+x2,y+y2);

	angle += 128;
#endif

	/* Time the anim */
	frame ++;

	GetSysTime (&time2);
	SubTime (&time2, &time1);

	sec = time2.tv_secs * 1000 + time2.tv_micro / 1000;

	if (sec)
	    fps = frame * 1000000 / sec;

	sprintf (string, "%4d %3d.%03d", frame, fps/1000, fps%1000);
	Graffiti_SetFG (gh, white);
	Graffiti_DrawText (gh, width-120, 230, string, 12);

	Graffiti_ShowNextBuffer (gh);
    }

    /* Exit demo */
    Graffiti_Exit (gh);

    printf ("%d frames\n", frame);
} /* main */
