#include "graffiti_intern.h"

#define ABSDIST(x,y)        (((x)>=(y))?((x)-(y)):((y)-(x)))
#define MATCH(r1,g1,b1,r2,g2,b2) \
	    ABSDIST(r1,r2) + ABSDIST(g1,g2) + ABSDIST(b1,b2)

UBYTE Graffiti_FindBestMatch_x (struct GraffitiHandle * gh, UBYTE r, UBYTE g,
	UBYTE b)
{
    UWORD try;
    UWORD col, match;
    UBYTE best;
    struct GraffitiColorMap * cm;

    cm = &gh->ColorMap[0];

    if (GD(gh)->colorcache)
    {
	/* we just try our last color. */
	match = MATCH(r,g,b,cm[GD(gh)->lastcolor].R,cm->G,cm->B);

	/* If the searched color matches equal or even better than the
	    last one, then the last color is what we're looking for. */
	if (match <= GD(gh)->lastmatch)
	    return GD(gh)->lastcolor;
    }

    best = 0;
    match = MATCH(r,g,b,cm->R,cm->G,cm->B);
    cm ++;

    if (!match)
	return 0;

    for (col=1; col<256; col++)
    {
	if (!cm->F)
	    continue;

	try = MATCH(r,g,b,cm->R,cm->G,cm->B);

	if (try < match)
	{
	    if (!try)
		return (UBYTE)col;

	    match = try;
	    best = col;
	}

	cm ++;
    }

    GD(gh)->colorcache = TRUE;
    GD(gh)->lastcolor = best;
    GD(gh)->lastmatch = match;

    return best;
} /* Graffiti_FindBestMatch */

UBYTE Graffiti_FindBestMatch_DefaultPalette (struct GraffitiHandle * gh,
	UBYTE r, UBYTE g, UBYTE b)
{
    /* grey ? */
    if ((r & 0xFC) == (g & 0xFC) && (r & 0xFC) == (b & 0xFC))
    {
#if 0
  printf ("g col=%d\n", _W3[r]);
#endif

	return ((UBYTE)(r>>2));
    }
    else if (r > b)
    {
	if (g > r)
	    return ((UBYTE)((g>>2) + 128));
	else
	    return ((UBYTE)((r>>2) + 64));
    }
    else
    {
	if (g > b)
	    return ((UBYTE)((g>>2) + 128));
	else
	    return ((UBYTE)((b>>2) + 192));
    }
} /* Graffiti_FindBestMatch_DefaultPalette */

void Graffiti_InstallDefaultPalette (struct GraffitiHandle * gh)
{
    int col, cnt;

    col = 0;

    Graffiti_BeginCmd (gh);

    /* Grey 0-63 */
    for (cnt=0; cnt<64; cnt++)
	Graffiti_SetRGB (gh, col++, cnt*4,cnt*4,cnt*4);

    /* Red 64-127 */
    for (cnt=0; cnt<64; cnt++)
	Graffiti_SetRGB (gh, col++, cnt*4,0,0);

    /* Green 128-191 */
    for (cnt=0; cnt<64; cnt++)
	Graffiti_SetRGB (gh, col++, 0,cnt*4,0);

    /* Blue 192-255 */
    for (cnt=0; cnt<64; cnt++)
	Graffiti_SetRGB (gh, col++, 0,0,cnt*4);

    Graffiti_EndCmd (gh);

    gh->FindBestMatch = Graffiti_FindBestMatch_DefaultPalette;

} /* Graffiti_InstallDefaultPalette */

void Graffiti_InstallPalette1 (struct GraffitiHandle * gh)
{
    int col, cnt, v;

    Graffiti_BeginCmd (gh);

    col = 0;

    /* Grey 0-31 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, v,v,v);
    }

    /* Red 32 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, v,0,0);
    }

    /* Gruen 64 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, 0,v,0);
    }

    /* Blau 96 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, 0,0,v);
    }

    /* Red/Gruen 128 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, v,v,0);
    }

    /* Rot/Blau 160 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, v,0,v);
    }

    /* Gruen/Blau 192 */
    for (cnt=0; cnt<32; cnt++)
    {
	v = cnt<<3;
	Graffiti_SetRGB (gh, col++, 0,v,v);
    }

    Graffiti_EndCmd (gh);

} /* Graffiti_InstallPalette1 */

void Graffiti_InstallPalette2 (struct GraffitiHandle * gh)
{
    static const UBYTE R[] = { 0x00, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xFF };
    static const UBYTE G[] = { 0x00, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xFF };
    static const UBYTE B[] = { 0x00, 0x50, 0xD0, 0xFF };
    int col, cnt;

    col = 0;

    Graffiti_BeginCmd (gh);

    for (cnt=0; cnt<256; cnt++)
    {
	Graffiti_SetRGB (gh, col++,
	    R[(cnt>>5)&0x07],
	    G[(cnt>>2)&0x07],
	    B[cnt&0x03]
	);
    }

    Graffiti_EndCmd (gh);

} /* Graffiti_InstallPalette2 */

static UBYTE _W3[256];
static UBYTE _R3[256];
static UBYTE _G3[256];
static UBYTE _B3[256];

UBYTE Graffiti_FindBestMatch_Palette3 (struct GraffitiHandle * gh,
	UBYTE r, UBYTE g, UBYTE b)
{
    /* grey ? */
    if ((r & 0xF0) == (g & 0xF0) && (r & 0xF0) == (b & 0xF0))
    {
#if 0
  printf ("g col=%d\n", _W3[r]);
#endif

	return _W3[r];
    }
    else
    {
/* printf ("c col=%d\n", _R3[r] + _G3[g] + _B3[b]); */
 /* printf ("c rgb=%d %d %d", r,g,b); */
#if 0
	r = ((UWORD)r*7)/256;
	g = ((UWORD)g*7)/256;
	b = ((UWORD)b*5)/256;

 /* printf (" (%d %d %d)", r,g,b); */

	r = r*35 + g*5 + b + 12;

 /* printf (" col=%d\n", r); */
#else
#if 0
	if (_R3[r] + _G3[g] + _B3[b] < 12)
	{
	    UBYTE col = _R3[r] + _G3[g] + _B3[b];
 printf ("c rgb=%d %d %d", r,g,b);
 printf (" col=%d (%d %d %d)\n", col,
	gh->ColorMap[col].R,
	gh->ColorMap[col].G,
	gh->ColorMap[col].B
	);
	}
#endif

	r = _R3[r] + _G3[g] + _B3[b];

  /* printf (" col=%d (%d %d %d)\n", r,
	gh->ColorMap[r].R,
	gh->ColorMap[r].G,
	gh->ColorMap[r].B
	); */
#endif
	return r;
    }
} /* Graffiti_FindBestMatch_Palette3 */

void Graffiti_InstallPalette3 (struct GraffitiHandle * gh)
{
    static const UBYTE R[] = { 0x00, 0x30, 0x50, 0x80, 0xB0, 0xD0, 0xFF };
    static const UBYTE G[] = { 0x00, 0x30, 0x50, 0x80, 0xB0, 0xD0, 0xFF };
    static const UBYTE B[] = { 0x00, 0x40, 0x80, 0xC0, 0xFF };
    int col, n, r, g, b;

    col = 0;

    Graffiti_BeginCmd (gh);

    for (r=1; r<12; r++, col++)
    {
	n = r*255/12;

	Graffiti_SetRGB (gh, col, n,n,n);
    }

    for (r=0; r<256; r++)
    {
	n = r*13/256;

	/* Remap black and white */
	if (n == 12)
	    n = 255;
	else if (!n)
	    n = 11;
	else
	    n --;

	_W3[r] = n;

	/* printf ("_W3[%d]=%d\n", r, n); */
    }

    for (r=0; r<7; r++)
    {
	for (g=0; g<7; g++)
	{
	    for (b=0; b<5; b++)
	    {
		Graffiti_SetRGB (gh, col++,
		    R[r],
		    G[g],
		    B[b]
		);
	    }
	}
    }

    for (r=0; r<256; r++)
    {
	n = r*6/255;

	_R3[r] = n*35;
    }

    for (g=0; g<256; g++)
    {
	n = g*6/255;

	_G3[g] = n*5;
    }

    for (b=0; b<256; b++)
    {
	n = b*4/255;

	_B3[b] = n + 11;
    }

    Graffiti_EndCmd (gh);

    gh->FindBestMatch = Graffiti_FindBestMatch_Palette3;

} /* Graffiti_InstallPalette3 */

