/***************************************************************************
  
  c_color.c
  
  (c) Benoît Minisini <benoit.minisini@gambas-basic.org>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  MA 02110-1301, USA.
  
***************************************************************************/

#define __C_COLOR_C

#include <math.h>
#include "c_color.h"

void gt_color_to_rgba(uint color, int *r, int *g, int *b, int *a)
{
	*b = color & 0xFF;
	*g = (color >> 8) & 0xFF;
	*r = (color >> 16) & 0xFF;
	*a = (color >> 24) & 0xFF;
}

static uint gt_rgba_to_color(int r, int g, int b, int a)
{
	return (uint)((uchar)b | ((uchar)g << 8) | ((uchar)r << 16) | ((uchar)a << 24));
}

void COLOR_rgb_to_hsv(int r, int g, int b, int *H, int *S, int *V)
{
	int min, max, diff;
	double rc, gc, bc, h;
	
	max = Max(r, Max(g, b));
	min = Min(r, Min(g, b));
	
	diff = max - min;
	
	if (diff == 0)
	{
		*H = -1;
		*S = 0;
		*V = min;
		return;
	}

	rc = (double)(max - r) / diff;
	gc = (double)(max - g) / diff;
	bc = (double)(max - b) / diff;
	
	if (r == max)
		h = bc - gc;
	else if (g == max)
		h = 2.0 + rc - bc;
	else
		h = 4.0 + gc - rc;
	
	*H = (int)(h * 60.0 + 360.4);
	if (*H >= 360) *H -= 360;
	*S = (int)((max - min) * 255.0 / max + 0.4);
	*V = (int)(max + 0.4);
}

static void gt_rgb_to_hsv_cached(int r, int g, int b, int *h, int *s, int *v)
{
	static int old_r = 0, old_g = 0, old_b = 0, old_h = -1, old_s = 0, old_v = 0;

	if (r == old_r && g == old_g && b == old_b)
	{
		*h = old_h;
		*s = old_s;
		*v = old_v;
		return;
	}

	COLOR_rgb_to_hsv(r, g, b, h, s, v);

	old_r = r;
	old_g = g;
	old_b = b;
	old_h = *h;
	old_s = *s;
	old_v = *v;
}

void COLOR_hsv_to_rgb(int h, int s, int v, int *R, int *G, int *B)
{
	double var_h;
	int var_i;
	int var_1, var_2, var_3;
	int tmp_r, tmp_g, tmp_b;

	if (h < 0)
		h = 360 - ((-h) % 360);
	else
		h = h % 360;

	 /*H = ((double)h) / 360;
	 S = ((double)s) / 255;
	 V = ((double)v) / 255;*/

	if (s == 0)
	{
		*R = v;
		*G = v;
		*B = v;
	}
	else
	{
		var_i = h / 60;
		var_h = h % 60; //((double)h / 60) - var_i;

		//var_1 = V * ( 1 - S );
		var_1 = v * (255 - s) / 255;

		//var_2 = V * ( 1 - S * ( var_h - var_i ) );
		var_2 = v * (255 - s * var_h / 60) / 255;

		//var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) );
		var_3 = v * (255 - s * (60 - var_h) / 60) / 255;

		switch (var_i)
		{
			case 0:
				tmp_r = v;
				tmp_g = var_3;
				tmp_b = var_1;
				break;

			case 1:
				tmp_r = var_2;
				tmp_g = v;
				tmp_b = var_1;
				break;

			case 2:
				tmp_r = var_1;
				tmp_g = v;
				tmp_b = var_3;
				break;

			case 3:
				tmp_r = var_1;
				tmp_g = var_2;
				tmp_b = v;
				break;

			case 4:
				tmp_r = var_3;
				tmp_g = var_1;
				tmp_b = v;
				break;

			default:
				tmp_r = v;
				tmp_g = var_1;
				tmp_b = var_2;
				break;
		}

		*R = tmp_r;
		*G = tmp_g;
		*B = tmp_b;

	}
}

static int get_luminance(CCOLOR *_object)
{
	return (int)(0.299 * THIS->r + 0.587 * THIS->g + 0.114 * THIS->b + 0.5);
}


int COLOR_get_luminance(GB_COLOR col)
{
	CCOLOR info;
	gt_color_to_rgba(col, &info.r, &info.g, &info.b, &info.a);
	return get_luminance(&info);
}


int COLOR_invert_luminance(int l)
{
	double m = 0.7;
	double d = l / 255.0;
	
	if (d < m)
		d = 1 - (d * (1 - m) / m);
	else
		d = (1 - d) * m / (1 - m);
	
	return (int)(255 * d);
}


static void set_luminance(CCOLOR *_object, int l)
{
	int c;
	
	if (l <= 0)
	{
		THIS->r = 0;
		THIS->g = 0;
		THIS->b = 0;
		return;
	}
	else if (l >= 255)
	{
		THIS->r = 255;
		THIS->g = 255;
		THIS->b = 255;
		return;
	}
	
	for(;;)
	{
		c = get_luminance(THIS);
		if (c == l)
			return;
		if (c == (l + 1) || c == (l - 1))
			break;
		THIS->r = MinMax(THIS->r + l - c, 0, 255);
		THIS->g = MinMax(THIS->g + l - c, 0, 255);
		THIS->b = MinMax(THIS->b + l - c, 0, 255);
	}
	
	THIS->g = MinMax(THIS->g + ((l > c) ? 1 : -1), 0, 255);
	c = get_luminance(THIS);
	if (c == l)
		return;
	
	THIS->r = MinMax(THIS->r + ((l > c) ? 1 : -1), 0, 255);
	c = get_luminance(THIS);
	if (c == l)
		return;
	
	THIS->b = MinMax(THIS->b + ((l > c) ? 1 : -1), 0, 255);
}


GB_COLOR COLOR_set_luminance(GB_COLOR col, int l)
{
	CCOLOR info;
	gt_color_to_rgba(col, &info.r, &info.g, &info.b, &info.a);
	set_luminance(&info, l);
	return gt_rgba_to_color(info.r, info.g, info.b, info.a);
}


GB_COLOR COLOR_merge(GB_COLOR col1, GB_COLOR col2, double weight)
{
	int r, g, b;
	int h1, s1, v1, a1;
	int h2, s2, v2, a2;
	
	if (weight == 0.0)
		return col1;
	else if (weight == 1.0)
		return col2;
	else
	{
		gt_color_to_rgba(col1, &r, &g, &b, &a1);
		COLOR_rgb_to_hsv(r, g, b, &h1, &s1, &v1);
		gt_color_to_rgba(col2, &r, &g, &b, &a2);
		COLOR_rgb_to_hsv(r, g, b, &h2, &s2, &v2);
		
		#define MIX(_val1, _val2) ((int)((_val1) * (1 - weight) + (_val2) * weight + 0.5))
		
		if (h1 < 0)
			h1 = h2;
		else if (h2 < 0)
			h2 = h1;
		else
			h1 = MIX(h1, h2);
		
		COLOR_hsv_to_rgb(h1, MIX(s1, s2), MIX(v1, v2), &r, &g, &b);
		
		return gt_rgba_to_color(r, g, b, MIX(a1, a2));
	}
}


GB_COLOR COLOR_gradient(GB_COLOR col1, GB_COLOR col2, double weight)
{
	int r1, g1, b1, a1;
	int r2, g2, b2, a2;
	
	if (weight == 0.0)
		return col1;
	else if (weight == 1.0)
		return col2;
	else
	{
		gt_color_to_rgba(col1, &r1, &g1, &b1, &a1);
		gt_color_to_rgba(col2, &r2, &g2, &b2, &a2);
		
		#define MIX(_val1, _val2) ((int)((_val1) * (1 - weight) + (_val2) * weight + 0.5))
		
		return gt_rgba_to_color(MIX(r1, r2), MIX(g1, g2), MIX(b1, b2), MIX(a1, a2));
	}
}


GB_COLOR COLOR_blend(GB_COLOR src, GB_COLOR dst, double opacity)
{
	uchar rs, gs, bs;
	uchar rd, gd, bd;
	uchar as = src >> 24;
	uchar ad = dst >> 24;

	as = MinMax((int)((as ^ 0xFF) * opacity + 0.5), 0, 255);
	
	if (as == 0)
		return dst;
	else if (as == 255)
		return src;
	
	ad ^= 0xFF;
	
	bs = src & 0xFF;
	gs = (src >> 8) & 0xFF;
	rs = (src >> 16) & 0xFF;
	
	bd = dst & 0xFF;
	gd = (dst >> 8) & 0xFF;
	rd = (dst >> 16) & 0xFF;
	
	// D = S * alpha(S) + D * (1 - alpha(S))
	
	bd = (((bs - bd) * as) >> 8) + bd;
	rd = (((rs - rd) * as) >> 8) + rd;
	gd = (((gs - gd) * as) >> 8) + gd;
	if (ad < as) ad = as;
	ad ^= 0xFF;
	
	return bd | (gd << 8) | (rd << 16) | (ad << 24);
}


GB_COLOR COLOR_lighter(GB_COLOR color)
{
  int h, s, v;
  int r, g, b, a;
  
	gt_color_to_rgba(color, &r, &g, &b, &a);
  COLOR_rgb_to_hsv(r, g, b, &h, &s, &v);
  COLOR_hsv_to_rgb(h, s / 2, 255 - (255 - v) / 2, &r, &g, &b);

  return gt_rgba_to_color(r, g, b, a);  
}


GB_COLOR COLOR_darker(GB_COLOR color)
{
  int h, s, v;
  int r, g, b, a;
  
	gt_color_to_rgba(color, &r, &g, &b, &a);
  COLOR_rgb_to_hsv(r, g, b, &h, &s, &v);
  COLOR_hsv_to_rgb(h, s ? 255 - (255 - s) / 2 : 0, v / 2, &r, &g, &b);

  v = gt_rgba_to_color(r, g, b, a);
	
	return v;
}


GB_COLOR COLOR_invert(GB_COLOR color, bool keep_hue)
{
	int r, g, b, a;
	int h, s, v;
	
	gt_color_to_rgba(color, &r, &g, &b, &a);

	if (keep_hue)
	{
		//return gt_rgba_to_color(255 - (g + b) / 2, 255 - (b + r) / 2, 255 - (r + g) / 2, a);
		
		COLOR_rgb_to_hsv(255 - r, 255 - g, 255 - b, &h, &s, &v);
		h = (h + 180) % 360;
		COLOR_hsv_to_rgb(h, s, v, &r, &g, &b);
		return gt_rgba_to_color(r, g, b, a);
	}
	else
	{
		return gt_rgba_to_color(255 - r, 255 - g, 255 - b, a);
	}
}

static double get_relative_luminance(GB_COLOR color)
{
	int r, g, b, a;
	double rs, gs, bs, as;
	double rl, gl, bl;
	
	gt_color_to_rgba(color, &r, &g, &b, &a);
	
	as = 1.0 - a / 255.0;
	rs = r / 255.0 * as;
	gs = g / 255.0 * as;
	bs = b / 255.0 * as;
	
	rl = (rs <= 0.03928) ? (rs / 12.92) : pow(((rs + 0.055) / 1.055), 2.4);
	gl = (gs <= 0.03928) ? (gs / 12.92) : pow(((gs + 0.055) / 1.055), 2.4);
	bl = (bs <= 0.03928) ? (bs / 12.92) : pow(((bs + 0.055) / 1.055), 2.4);
	
	return 0.2126 * rl + 0.7152 * gl + 0.0722 * bl;
}

//-------------------------------------------------------------------------

BEGIN_METHOD(Color_RGB, GB_INTEGER r; GB_INTEGER g; GB_INTEGER b; GB_INTEGER a)

  GB.ReturnInteger(gt_rgba_to_color(VARG(r), VARG(g), VARG(b), VARGOPT(a, 0)));

END_METHOD

BEGIN_METHOD(Color_SetRGB, GB_INTEGER color; GB_INTEGER red; GB_INTEGER green; GB_INTEGER blue; GB_INTEGER alpha)

	int r, g, b, a;
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
  GB.ReturnInteger(gt_rgba_to_color(VARGOPT(red, r), VARGOPT(green, g), VARGOPT(blue, b), VARGOPT(alpha, a)));

END_METHOD

BEGIN_METHOD(Color_HSV, GB_INTEGER h; GB_INTEGER s; GB_INTEGER v; GB_INTEGER a)

	int r, g, b;
	COLOR_hsv_to_rgb(VARG(h), VARG(s), VARG(v), &r, &g, &b);
  GB.ReturnInteger(gt_rgba_to_color(r, g, b, VARGOPT(a, 0)));

END_METHOD

BEGIN_METHOD(Color_SetHSV, GB_INTEGER color; GB_INTEGER hue; GB_INTEGER saturation; GB_INTEGER value; GB_INTEGER alpha)

	int r, g, b, a, h, s, v;
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	gt_rgb_to_hsv_cached(r, g, b, &h, &s, &v);
	COLOR_hsv_to_rgb(VARGOPT(hue, h), VARGOPT(saturation, s), VARGOPT(value, v), &r, &g, &b);
  GB.ReturnInteger(gt_rgba_to_color(r, g, b, VARGOPT(alpha, a)));

END_METHOD

BEGIN_METHOD(Color_get, GB_INTEGER color)

	static GB_CLASS klass = 0;
	CCOLOR *info;

	if (!klass) klass = GB.FindClass("ColorInfo");
	info = GB.New(klass, NULL, NULL);
	
	gt_color_to_rgba(VARG(color), &info->r, &info->g, &info->b, &info->a);
  GB.ReturnObject(info);

END_METHOD

static void handle_rgba_property(CCOLOR *_object, void *_param, int prop)
{
	if (READ_PROPERTY)
	{
		switch(prop)
		{
			case CC_R: GB.ReturnInteger(THIS->r); break;
			case CC_G: GB.ReturnInteger(THIS->g); break;
			case CC_B: GB.ReturnInteger(THIS->b); break;
			case CC_A: GB.ReturnInteger(THIS->a); break;
		}
	}
	else
	{
		int v = VPROP(GB_INTEGER);
		if (v < 0) v = 0; else if (v > 255) v = 255;
		switch(prop)
		{
			case CC_R: THIS->r = v; break;
			case CC_G: THIS->g = v; break;
			case CC_B: THIS->b = v; break;
			case CC_A: THIS->a = v; break;
		}
	}
}

BEGIN_PROPERTY(ColorInfo_Alpha)

	handle_rgba_property(_object, _param, CC_A);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Red)

	handle_rgba_property(_object, _param, CC_R);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Green)

	handle_rgba_property(_object, _param, CC_G);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Blue)

	handle_rgba_property(_object, _param, CC_B);

END_PROPERTY

static void handle_hsv_property(CCOLOR *_object, void *_param, int prop)
{
  int h, s, v;
  gt_rgb_to_hsv_cached(THIS->r, THIS->g, THIS->b, &h, &s, &v);
	
	if (READ_PROPERTY)
	{
		switch(prop)
		{
			case CC_H: GB.ReturnInteger(h); break;
			case CC_V: GB.ReturnInteger(v); break;
			case CC_S: GB.ReturnInteger(s); break;
		}
	}
	else
	{
		switch(prop)
		{
			case CC_H: h = VPROP(GB_INTEGER) % 360; break;
			case CC_V: v = VPROP(GB_INTEGER); if (v < 0) v = 0; else if (v > 255) v = 255; break;
			case CC_S: s = VPROP(GB_INTEGER); if (s < 0) s = 0; else if (s > 255) s = 255; break;
		}
		COLOR_hsv_to_rgb(h, s, v, &THIS->r, &THIS->g, &THIS->b);
	}
}

BEGIN_PROPERTY(ColorInfo_Hue)

	handle_hsv_property(THIS, _param, CC_H);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Saturation)

	handle_hsv_property(THIS, _param, CC_S);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Value)

	handle_hsv_property(THIS, _param, CC_V);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Color)

	CCOLOR *info = THIS;

	if (READ_PROPERTY)
		GB.ReturnInteger(gt_rgba_to_color(info->r, info->g, info->b, info->a));
	else
		gt_color_to_rgba(VPROP(GB_INTEGER), &info->r, &info->g, &info->b, &info->a);

END_PROPERTY

BEGIN_PROPERTY(ColorInfo_Luminance)

	if (READ_PROPERTY)
		GB.ReturnInteger(get_luminance(THIS));
	else
		set_luminance(THIS, VPROP(GB_INTEGER));

END_PROPERTY

//---------------------------------------------------------------------------

BEGIN_METHOD(Color_Lighter, GB_INTEGER color)

  GB.ReturnInteger(COLOR_lighter(VARG(color)));
  
END_METHOD

BEGIN_METHOD(Color_Darker, GB_INTEGER color)

  GB.ReturnInteger(COLOR_darker(VARG(color)));

END_METHOD

BEGIN_METHOD(Color_Merge, GB_INTEGER color1; GB_INTEGER color2; GB_FLOAT weight)

	GB.ReturnInteger(COLOR_merge(VARG(color1), VARG(color2), VARGOPT(weight, 0.5)));

END_METHOD

BEGIN_METHOD(Color_Gradient, GB_INTEGER color1; GB_INTEGER color2; GB_FLOAT weight)

	GB.ReturnInteger(COLOR_gradient(VARG(color1), VARG(color2), VARGOPT(weight, 0.5)));

END_METHOD

BEGIN_METHOD(Color_Desaturate, GB_INTEGER color)

	int r, g, b, a, gray;
	
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	gray = (r * 11 + g * 16 + b * 5) / 32;
	GB.ReturnInteger(gt_rgba_to_color(gray, gray, gray, a));

END_METHOD

BEGIN_METHOD(Color_Blend, GB_INTEGER src; GB_INTEGER dst; GB_FLOAT opacity)

	GB.ReturnInteger(COLOR_blend(VARG(src), VARG(dst), VARGOPT(opacity, 1.0)));

END_METHOD

BEGIN_METHOD(Color_GetAlpha, GB_INTEGER color)

	int r, g, b, a;
	
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	GB.ReturnInteger(a);

END_METHOD

BEGIN_METHOD(Color_SetAlpha, GB_INTEGER color; GB_INTEGER alpha)

	int r, g, b, a;
	
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	a = VARG(alpha);
	GB.ReturnInteger(gt_rgba_to_color(r, g, b, a));

END_METHOD

BEGIN_METHOD(Color_Distance, GB_INTEGER col1; GB_INTEGER col2)

	int r1, g1, b1, a1;
	int r2, g2, b2, a2;

	gt_color_to_rgba(VARG(col1), &r1, &g1, &b1, &a1);
	gt_color_to_rgba(VARG(col2), &r2, &g2, &b2, &a2);

	r1 -= r2;
	g1 -= g2;
	b1 -= b2;
	a1 -= a2;
	r1 *= r1;
	g1 *= g1;
	b1 *= b1;
	a1 *= a1;

	GB.ReturnFloat(sqrt(r1 + b1 + g1 + a1) / 510.0);

END_METHOD

#if 0

Private Sub GetContrast(iCol1 As Integer, iCol2 As Integer) As Float

  Dim fCol1 As Float
  Dim fCol2 As Float
  Dim fContrast As Float

  fCol1 = GetRelativeLuminance(iCol1)
  fCol2 = GetRelativeLuminance(iCol2)
  fContrast = (fCol1 + 0.05) / (fCol2 + 0.05)
  If fContrast < 1 Then fContrast = 1 / fContrast
  Return fContrast

End
#endif

BEGIN_METHOD(Color_Contrast, GB_INTEGER col1; GB_INTEGER col2)

	double l1 = get_relative_luminance(VARG(col1));
	double l2 = get_relative_luminance(VARG(col2));
	double c;
	
	if (l1 > l2)
		c = (l1 + 0.05) / (l2 + 0.05);
	else
		c = (l2 + 0.05) / (l1 + 0.05);
	
	GB.ReturnFloat((c - 1) / 20.0);

END_METHOD


BEGIN_METHOD(Color_Invert, GB_INTEGER color; GB_BOOLEAN keep_hue)

  GB.ReturnInteger(COLOR_invert(VARG(color), VARGOPT(keep_hue, FALSE)));

END_METHOD


BEGIN_METHOD(Color_ToHTML, GB_INTEGER color)

	char buffer[32];
	int r, g, b, a;
	int len;

	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	a = 255 - a;

	if (a < 255)
		len = sprintf(buffer, "rgba(%d,%d,%d,0.%03d)", r, g, b, (int)(a / 255.0 * 1000));
	else
		len = sprintf(buffer, "#%02X%02X%02X", r, g, b);

	GB.ReturnNewString(buffer, len);

END_METHOD


BEGIN_METHOD(Color_Opacity, GB_INTEGER color; GB_FLOAT opacity)

	int r, g, b, a;
	
	gt_color_to_rgba(VARG(color), &r, &g, &b, &a);
	
	a = (int)((a ^ 0xFF) * VARG(opacity) + 0.5);
	a = MinMax(a, 0, 255) ^ 0xFF;
	
	GB.ReturnInteger(gt_rgba_to_color(r, g, b, a));

END_METHOD

//-------------------------------------------------------------------------

GB_DESC ColorInfoDesc[] =
{
  GB_DECLARE("ColorInfo", sizeof(CCOLOR)), GB_NOT_CREATABLE(),

  GB_PROPERTY("Alpha", "i", ColorInfo_Alpha),
  GB_PROPERTY("Red", "i", ColorInfo_Red),
  GB_PROPERTY("Green", "i", ColorInfo_Green),
  GB_PROPERTY("Blue", "i", ColorInfo_Blue),
  GB_PROPERTY("Hue", "i", ColorInfo_Hue),
  GB_PROPERTY("Saturation", "i", ColorInfo_Saturation),
  GB_PROPERTY("Value", "i", ColorInfo_Value),
  GB_PROPERTY("Color", "i", ColorInfo_Color),
  GB_PROPERTY("Luminance", "i", ColorInfo_Luminance),
  
  GB_END_DECLARE
};

GB_DESC ColorDesc[] =
{
  GB_DECLARE_STATIC("Color"),

  GB_CONSTANT("Default", "i", GB_COLOR_DEFAULT),

  GB_CONSTANT("Black", "i", 0x000000),
  GB_CONSTANT("White", "i", 0xFFFFFF),
  
  GB_CONSTANT("LightGray", "i", 0xC0C0C0),
  GB_CONSTANT("Gray", "i", 0x808080),
  GB_CONSTANT("DarkGray", "i", 0x404040),

  GB_CONSTANT("Blue", "i", 0x0000FF),
  GB_CONSTANT("DarkBlue", "i", 0x000080),
  GB_CONSTANT("SoftBlue", "i", 0x8080FF),

  GB_CONSTANT("Green", "i", 0x00FF00),
  GB_CONSTANT("DarkGreen", "i", 0x008000),
  GB_CONSTANT("SoftGreen", "i", 0x80FF80),

  GB_CONSTANT("Red", "i", 0xFF0000),
  GB_CONSTANT("DarkRed", "i", 0x800000),
  GB_CONSTANT("SoftRed", "i", 0xFF8080),

  GB_CONSTANT("Cyan", "i", 0x00FFFF),
  GB_CONSTANT("DarkCyan", "i", 0x008080),
  GB_CONSTANT("SoftCyan", "i", 0x80FFFF),

  GB_CONSTANT("Magenta", "i", 0xFF00FF),
  GB_CONSTANT("DarkMagenta", "i", 0x800080),
  GB_CONSTANT("SoftMagenta", "i", 0xFF80FF),
  GB_CONSTANT("Pink", "i", 0xFF80FF),

  GB_CONSTANT("Yellow", "i", 0xFFFF00),
  GB_CONSTANT("DarkYellow", "i", 0x808000),
  GB_CONSTANT("SoftYellow", "i", 0xFFFF80),

  GB_CONSTANT("Orange", "i", 0xFF8000),
  GB_CONSTANT("DarkOrange", "i", 0x804000),
  GB_CONSTANT("SoftOrange", "i", 0xFFC080),
  
  GB_CONSTANT("Violet", "i", 0x8000FF),
  GB_CONSTANT("DarkViolet", "i", 0x400080),
  GB_CONSTANT("SoftViolet", "i", 0xC080FF),

  GB_CONSTANT("Royal", "i", 0x0080FF),
  GB_CONSTANT("DarkRoyal", "i", 0x004080),
  GB_CONSTANT("SoftRoyal", "i", 0x80C0FF),

  GB_CONSTANT("Purple", "i", 0xFF0080),
  GB_CONSTANT("DarkPurple", "i", 0x800040),
  GB_CONSTANT("SoftPurple", "i", 0xFF80C0),

  GB_CONSTANT("Transparent", "i", GB_COLOR_TRANSPARENT),

  GB_STATIC_METHOD("RGB", "i", Color_RGB, "(Red)i(Green)i(Blue)i[(Alpha)i]"),
  GB_STATIC_METHOD("HSV", "i", Color_HSV, "(Hue)i(Saturation)i(Value)i[(Alpha)i]"),
  GB_STATIC_METHOD("_call", "i", Color_RGB, "(Red)i(Green)i(Blue)i[(Alpha)i]"),

  GB_STATIC_METHOD("Lighter", "i", Color_Lighter, "(Color)i"),
  GB_STATIC_METHOD("Darker", "i", Color_Darker, "(Color)i"),
  GB_STATIC_METHOD("Merge", "i", Color_Merge, "(Color1)i(Color2)i[(Weight)f]"),
  GB_STATIC_METHOD("Gradient", "i", Color_Gradient, "(Color1)i(Color2)i[(Weight)f]"),
  GB_STATIC_METHOD("Blend", "i", Color_Blend, "(Source)i(Destination)i[(Opacity)f]"),
  GB_STATIC_METHOD("Desaturate", "i", Color_Desaturate, "(Color)i"),
  GB_STATIC_METHOD("Invert", "i", Color_Invert, "(Color)i[(KeepHue)b]"),
	GB_STATIC_METHOD("Opacity", "i", Color_Opacity, "(Color)i(Opacity)f"),

	GB_STATIC_METHOD("SetAlpha", "i", Color_SetAlpha, "(Color)i(Alpha)i"),
	GB_STATIC_METHOD("SetRGB", "i", Color_SetRGB, "(Color)i[(Red)i(Green)i(Blue)i(Alpha)i]"),
	GB_STATIC_METHOD("SetHSV", "i", Color_SetHSV, "(Color)i[(Hue)i(Saturation)i(Value)i(Alpha)i]"),
	GB_STATIC_METHOD("GetAlpha", "i", Color_GetAlpha, "(Color)i"),

  GB_STATIC_METHOD("Distance", "f", Color_Distance, "(Color1)i(Color2)i"),
  GB_STATIC_METHOD("Contrast", "f", Color_Contrast, "(Color1)i(Color2)i"),

  GB_STATIC_METHOD("ToHTML", "s", Color_ToHTML, "(Color)i"),

  GB_STATIC_METHOD("_get", "ColorInfo", Color_get, "(Color)i"),
  //GB_STATIC_METHOD("_call", "ColorInfo", Color_get, "(Color)i"),
	
  GB_END_DECLARE
};


