#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos/dos.h>
#include <utility/hooks.h>
#include "graffiti.h"

#include <proto/exec.h>
#include <proto/dos.h>

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

#define ABSDIST(a,b)        (((a) >= (b))?((a)-(b)):((b)-(a)))

ULONG __saveds __asm SetPixelHook (register __a0 struct Hook * hook,
    register __a2 struct GraffitiHandle * gh,
    register __a1 struct GraffitiHookData * ghd)
{
/* printf ("SetPixelHook: Pos=%d,%d Col=%d\n",
    ghd->x, ghd->y, ghd->col); */

    Graffiti_SetPixelColor (gh, ghd->x1+ghd->x, ghd->y1+ghd->y, ghd->col);

    return 0;
} /* SetPixelHook */

ULONG __saveds __asm AlphaHook (register __a0 struct Hook * hook,
    register __a2 struct GraffitiHandle * gh,
    register __a1 struct GraffitiHookData * ghd)
{
    UWORD a = 0x80;
    UWORD r, g, b;
    UWORD pcol;

    pcol = Graffiti_GetPixel (gh, ghd->x1+ghd->x, ghd->y1+ghd->y);

    r = ((gh->ColorMap[pcol].R * a) >> 8) +
	((gh->ColorMap[ghd->col].R * (0xFF-a)) >> 8);
    g = ((gh->ColorMap[pcol].G * a) >> 8) +
	((gh->ColorMap[ghd->col].G * (0xFF-a)) >> 8);
    b = ((gh->ColorMap[pcol].B * a) >> 8) +
	((gh->ColorMap[ghd->col].B * (0xFF-a)) >> 8);

    ghd->col = Graffiti_FindBestMatch (gh, r, g, b);

/* printf ("AlphaHook: In: Pos=%d,%d G=%02x A=%02x Out: G=%02x Col=%d\n",
	ghd->x, ghd->y, gh->ColorMap[pcol].G, a, g, ghd->col); */

    return ghd->col;
} /* AlphaHook */

ULONG __saveds __asm AlphaBlendHook (register __a0 struct Hook * hook,
    register __a2 struct GraffitiHandle * gh,
    register __a1 struct GraffitiHookData * ghd)
{
    ULONG width, height;

    width = ABSDIST(ghd->x2,ghd->x1)+1;
    height = ABSDIST(ghd->y2,ghd->y1)+1;

    if (!width)
    {
	if (!height)
	    ghd->arg0 = 0x80;
	else
	    ghd->arg0 = (ghd->y << 8) / height;
    }
    else if (!height)
    {
	ghd->arg0 = (ghd->x << 8) / width;
    }
    else
    {
	ghd->arg0 = ((ghd->x << 8) / width + (ghd->y << 8) / height) >> 1;

	/* ghd->arg0 = (((height * ghd->y) + (width * ghd->x)) << 8) /
		(height * height + width * width); */
    }

/* printf ("AlphaBlendHook: Pos=%d,%d A=%02x\n", ghd->x, ghd->y, ghd->arg0); */

    return ghd->arg0;
} /* AlphaBlendHook */

ULONG __saveds __asm QAlphaBlendHook (register __a0 struct Hook * hook,
    register __a2 struct GraffitiHandle * gh,
    register __a1 struct GraffitiHookData * ghd)
{
    ULONG width, height;
    UWORD r, g, b, a;
    UWORD pcol;

    /* This not exactly the width, but the value should be the
       max value of ghd->x and ghd->y resp. */
    width = ABSDIST(ghd->x2,ghd->x1);
    height = ABSDIST(ghd->y2,ghd->y1);

    if (!width)
    {
	if (!height)
	    a = 0x80;
	else
	    a = (ghd->y << 8) / height;
    }
    else if (!height)
    {
	a = (ghd->x << 8) / width;
    }
    else
    {
	a = ((ghd->x << 8) / width + (ghd->y << 8) / height) >> 1;

	/* a = (((height * ghd->y) + (width * ghd->x)) << 8) /
		(height * height + width * width); */

	if (a > 0xFF)
	{
 /* printf ("QAlphaBlendHook: Pos=%d,%d Size=%d,%d A=%x\n", ghd->x, ghd->y,
	width, height,
	a); */
	    a = 0xFF;
	}
    }

 /* printf ("QAlphaBlendHook: Pos=%d,%d A=%02x\n", ghd->x, ghd->y,
	a); */

    pcol = Graffiti_GetPixel (gh, ghd->x1+ghd->x, ghd->y1+ghd->y);

    r = ((gh->ColorMap[pcol].R * a) >> 8) +
	((gh->ColorMap[ghd->col].R * (0xFF-a)) >> 8);
    g = ((gh->ColorMap[pcol].G * a) >> 8) +
	((gh->ColorMap[ghd->col].G * (0xFF-a)) >> 8);
    b = ((gh->ColorMap[pcol].B * a) >> 8) +
	((gh->ColorMap[ghd->col].B * (0xFF-a)) >> 8);

    ghd->col = Graffiti_FindBestMatch (gh, r, g, b);

/* printf ("QAlphaHook: In: Pos=%d,%d G=%02x A=%02x Out: G=%02x Col=%d\n",
	ghd->x, ghd->y, gh->ColorMap[pcol].G, a, g, ghd->col); */

    Graffiti_SetPixelColor (gh, ghd->x1+ghd->x, ghd->y1+ghd->y, ghd->col);

    return ghd->col;
} /* QAlphaBlendHook */

void WaitForUser (struct GraffitiHandle * gh)
{
    static const char text[] = "Please press mousebutton"; /* len=24 */
    struct IntuiMessage * im = NULL;
    int t, pos, done, off, x, dir;
    int col[4];

    col[3] = Graffiti_FindBestMatch (gh, 255,255,255);
    col[2] = Graffiti_FindBestMatch (gh, 255,200,200);
    col[1] = Graffiti_FindBestMatch (gh, 255,150,150);
    col[0] = Graffiti_FindBestMatch (gh, 255,100,100);

    pos = 0;
    dir = +1;
    done = FALSE;

    while (!done)
    {
	x = 128;

	for (t=0; t<24; t++)
	{
	    off = t-pos;
	    if (off < 0) off = -off;
	    if (off > 3) off = 3;

	    Graffiti_SetFG (gh, col[off]);
	    Graffiti_DrawText (gh, x, 248, (STRPTR)&text[t], 1);

	    x += 8;
	}

	pos += dir;

	if (dir > 0)
	{
	    if (pos == 23)
		dir = -1;
	}
	else
	{
	    if (pos == 0)
		dir = +1;
	}

	for (t=0; t<2 && !done; t++)
	{
	    im = Graffiti_CheckEvent (gh);

	    if (im)
		done = TRUE;
	    else
		Delay (1);
	}
    }

    if (im)
	ReplyMsg ((struct Message *)im);

} /* WaitForUser */

ULONG width;

void CenterText (struct GraffitiHandle * gh, char * text, UWORD y, UBYTE col)
{
    UWORD x, len;

    x = width/2 - (len=strlen(text))*4;

    Graffiti_SetFG (gh, col);
    Graffiti_DrawText (gh, x, y, text, len);
}

int main (int argc, char ** argv)
{
    struct GraffitiHandle * gh;
    int mode;
    int white;
    int x, y, w, h, t, i, w2, h2, w3, h3;
    int xoff, yoff;
    int x2, y2, x3, y3, col;

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

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

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

    if (!gh)
    {
	fprintf (stderr, "Cannot init grafitti\n");
	return 0;
    }

    Graffiti_GetAttr (gh, GTI_WIDTH, &width);

    /* Install palette with some reasonable values. */
    Graffiti_InstallPalette3 (gh);

    /* Find color id for white */
    white = Graffiti_FindBestMatch (gh, 255, 255, 255);

    CenterText (gh, "Welcome to the Demo for the Graffiti lib", 0, white);
    Graffiti_SetFG (gh, white);
    Graffiti_DrawLine (gh, 0, 10, width, 10);

    CenterText (gh, "This demo shows some of the abilities of", 20, white);
    CenterText (gh, "the Graffiti lib.", 28, white);

    /* Draw boxes */
    w = (width-1) / 4;
    h = 200 / 3;
    w2 = w - 9;
    h2 = h - 9;
    xoff = 0;
    yoff = 40;

    Graffiti_SetFG (gh, white);

    for (i=0; i<3; i++)
	for (t=0; t<4; t++)
	    Graffiti_DrawRect (gh,
		t*w+xoff, i*h+yoff,
		(t+1)*w+xoff, (i+1)*h+yoff
	    );

    xoff = 5;
    yoff = 45;
    col = 1;

    /* Demo1: Lines */
    x = 0 * w + xoff;
    y = 0 * h + yoff;

    for (t=0; t<w2; t++)
    {
	Graffiti_SetFG (gh, col++);
	Graffiti_DrawLine (gh, x+t, y, x+w2-t, y+h2);
    }

    for (t=0; t<h2; t++)
    {
	Graffiti_SetFG (gh, col++);
	Graffiti_DrawLine (gh, x, y+t, x+w2, y+h2-t);
    }

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-5*4, y+h2-8, "Lines", 5);

    /* Demo2: DrawRect */
    x = 1 * w + xoff;
    y = 0 * h + yoff;

    for (t=0; t<16; t++)
    {
	x2 = t & 3;
	y2 = t >> 2;

	x3 = x + (x2+1)*w2/4-1;
	y3 = y + (y2+1)*h2/4-1;
	x2 = x + x2*w2/4;
	y2 = y + y2*h2/4;

	Graffiti_SetFG (gh, col++);
	Graffiti_DrawRect (gh, x2, y2, x3, y3);
    }

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-9*4, y+h2-8, "Rectangle", 9);

    /* Demo3: FillRect */
    x = 2 * w + xoff;
    y = 0 * h + yoff;

    for (t=0; t<16; t++)
    {
	x2 = t & 3;
	y2 = t >> 2;

	x3 = x + (x2+1)*w2/4-1;
	y3 = y + (y2+1)*h2/4-1;
	x2 = x + x2*w2/4;
	y2 = y + y2*h2/4;

	Graffiti_SetFG (gh, col++);
	Graffiti_FillRect (gh, x2, y2, x3, y3);
    }

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-6*4, y+h2-16, "Filled", 6);
    Graffiti_DrawText (gh, x+w2/2-9*4, y+h2-8,  "Rectangle", 9);

    /* Demo4: Ellipse */
    x = 3 * w + xoff;
    y = 0 * h + yoff;
    w3 = w2/2;
    h3 = h2/2;
    x2 = x + w3;
    y2 = y + h3;

    for (t=0; t<=5; t++)
    {
	Graffiti_SetFG (gh, col++);
	Graffiti_DrawEllipse (gh, x2, y2, t*w3/5, (5-t)*h3/5);
    }

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-8, "Ellipse", 7);

    /* Demo5: Filled Ellipse */
    x = 0 * w + xoff;
    y = 1 * h + yoff;
    w3 = w2/2;
    h3 = h2/2;
    x2 = x + w3;
    y2 = y + h3;

    for (t=0; t<=5; t++)
    {
	Graffiti_SetFG (gh, col++);
	Graffiti_FillEllipse (gh, x2, y2, t*w3/5, (5-t)*h3/5);
    }

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-6*4, y+h2-16, "Filled", 6);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-8,  "Ellipse", 7);

    /* Demo6: General Ellipse */
    x = 1 * w + xoff;
    y = 1 * h + yoff;
    x2 = x+w2/2;
    y2 = y+h2/2;

    Graffiti_SetClip (gh, x, y, x+w2-1, y+h2-1);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawGenEllipse (gh, x2, y2, w2/2, h2/4, 2000);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawGenEllipse (gh, x2, y2, w2/2, h2/4, 4000);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawGenEllipse (gh, x2, y2, w2/2, h2/4, 6000);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawGenEllipse (gh, x2, y2, w2/2, h2/4, 8000);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawGenEllipse (gh, x2, y2, w2/2, h2/4, 10000);
    Graffiti_SetClip (gh, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-16, "General", 7);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-8,  "Ellipse", 7);

    /* Demo6: Filled General Ellipse */
    x = 2 * w + xoff;
    y = 1 * h + yoff;
    x2 = x+w2/2;
    y2 = y+h2/2;

    Graffiti_SetClip (gh, x, y, x+w2-1, y+h2-1);
    Graffiti_SetFG (gh, col++);
    Graffiti_FillGenEllipse (gh, x2, y2, w2/2, h2/4, 2000);
    Graffiti_SetFG (gh, col++);
    Graffiti_FillGenEllipse (gh, x2, y2, w2/2, h2/4, 4000);
    Graffiti_SetFG (gh, col++);
    Graffiti_FillGenEllipse (gh, x2, y2, w2/2, h2/4, 6000);
    Graffiti_SetFG (gh, col++);
    Graffiti_FillGenEllipse (gh, x2, y2, w2/2, h2/4, 8000);
    Graffiti_SetFG (gh, col++);
    Graffiti_FillGenEllipse (gh, x2, y2, w2/2, h2/4, 10000);
    Graffiti_SetClip (gh, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-6*4, y+h2-24, "Filled", 6);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-16, "General", 7);
    Graffiti_DrawText (gh, x+w2/2-7*4, y+h2-8,  "Ellipse", 7);

    /* Demo7: Text */
    x = 3 * w + xoff;
    y = 1 * h + yoff;

    Graffiti_SetFG (gh, col++);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+ 0, "Text", 4);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+ 8, "Text", 4);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+16, "Text", 4);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+24, "Text", 4);

    /* To understand why these two lines give a striped text, you
	must have a look at Topaz.gfont */
    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+32, "Text", 4);
    Graffiti_SetFG (gh, col++);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+32, "مممم", 4);

    Graffiti_SetFG (gh, white);
    Graffiti_DrawText (gh, x+w2/2-4*4, y+h2-8,  "Text", 4);

    /* Remove frame */
    xoff -= 5;
    yoff -= 5;
    w2 += 9;
    h2 += 9;

    /* Demo8: empty */
    x = 0 * w + xoff;
    y = 2 * h + yoff;

    Graffiti_SetFG (gh, white);
    Graffiti_DrawLine (gh, x, y, x+w2, y+h2);
    Graffiti_DrawLine (gh, x+w2, y, x, y+h2);

    /* Demo9: empty */
    x = 1 * w + xoff;
    y = 2 * h + yoff;

    Graffiti_SetFG (gh, white);
    Graffiti_DrawLine (gh, x, y, x+w2, y+h2);
    Graffiti_DrawLine (gh, x+w2, y, x, y+h2);

    /* Demo10: empty */
    x = 2 * w + xoff;
    y = 2 * h + yoff;

    Graffiti_SetFG (gh, white);
    Graffiti_DrawLine (gh, x, y, x+w2, y+h2);
    Graffiti_DrawLine (gh, x+w2, y, x, y+h2);

    /* Demo11: empty */
    x = 3 * w + xoff;
    y = 2 * h + yoff;

    Graffiti_SetFG (gh, white);
    Graffiti_DrawLine (gh, x, y, x+w2, y+h2);
    Graffiti_DrawLine (gh, x+w2, y, x, y+h2);

    /* End Frame 1 */
    WaitForUser (gh);

    /* Exit demo */
    Graffiti_Exit (gh);

} /* main */
