Browse Source

Added Color.h

Karroffel 8 years ago
parent
commit
1d61c9df93
1 changed files with 467 additions and 0 deletions
  1. 467 0
      include/godot/core/Color.h

+ 467 - 0
include/godot/core/Color.h

@@ -0,0 +1,467 @@
+#ifndef COLOR_H
+#define COLOR_H
+
+#include <godot/godot_color.h>
+
+#include <cmath>
+
+#include <String.h>
+
+namespace godot {
+
+// @Todo move these to a more global file.
+
+// or should I? 🤔
+#define MIN(a, b) (a < b ? a : b)
+#define MAX(a, b) (a > b ? a : b)
+
+struct Color {
+
+
+private:
+	static float _parse_col(const String& p_str, int p_ofs) {
+
+		int ig=0;
+
+		for(int i=0;i<2;i++) {
+
+			int c= (int) (wchar_t) p_str[i+p_ofs];
+			int v=0;
+
+			if (c>='0' && c<='9') {
+				v=c-'0';
+			} else if (c>='a' && c<='f') {
+				v=c-'a';
+				v+=10;
+			} else if (c>='A' && c<='F') {
+				v=c-'A';
+				v+=10;
+			} else {
+				return -1;
+			}
+
+			if (i==0)
+				ig+=v*16;
+			else
+				ig+=v;
+
+		}
+
+		return ig;
+
+	}
+public:
+
+	union {
+
+		struct {
+			float r;
+			float g;
+			float b;
+			float a;
+		};
+		float components[4];
+	};
+
+	bool operator==(const Color &p_color) const { return (r==p_color.r && g==p_color.g && b==p_color.b && a==p_color.a ); }
+	bool operator!=(const Color &p_color) const { return (r!=p_color.r || g!=p_color.g || b!=p_color.b || a!=p_color.a ); }
+
+	uint32_t to_32() const
+	{
+
+		uint32_t c=(uint8_t)(a*255);
+		c<<=8;
+		c|=(uint8_t)(r*255);
+		c<<=8;
+		c|=(uint8_t)(g*255);
+		c<<=8;
+		c|=(uint8_t)(b*255);
+
+		return c;
+	}
+
+	uint32_t to_ARGB32() const
+	{
+		uint32_t c=(uint8_t)(a*255);
+		c<<=8;
+		c|=(uint8_t)(r*255);
+		c<<=8;
+		c|=(uint8_t)(g*255);
+		c<<=8;
+		c|=(uint8_t)(b*255);
+
+		return c;
+	}
+
+	float gray() const
+	{
+		return (r+g+b)/3.0;
+	}
+
+	float get_h() const
+	{
+
+		float min = MIN( r, g );
+		min = MIN( min, b );
+		float max = MAX( r, g );
+		max = MAX( max, b );
+
+		float delta = max - min;
+
+		if( delta == 0 )
+			return 0;
+
+		float h;
+		if( r == max )
+			h = ( g - b ) / delta;		// between yellow & magenta
+		else if( g == max )
+			h = 2 + ( b - r ) / delta;	// between cyan & yellow
+		else
+			h = 4 + ( r - g ) / delta;	// between magenta & cyan
+
+		h/=6.0;
+		if (h<0)
+			h+=1.0;
+
+		return h;
+	}
+
+	float get_s() const
+	{
+		float min = MIN( r, g );
+		min = MIN( min, b );
+		float max = MAX( r, g );
+		max = MAX( max, b );
+		float delta = max - min;
+		return (max!=0) ? (delta / max) : 0;
+
+	}
+
+	float get_v() const
+	{
+		float max = MAX( r, g );
+		max = MAX( max, b );
+		return max;
+	}
+
+	void set_hsv(float p_h, float p_s, float p_v, float p_alpha=1.0)
+	{
+		int i;
+		float f, p, q, t;
+		a=p_alpha;
+
+		if( p_s == 0 ) {
+			// acp_hromatic (grey)
+			r = g = b = p_v;
+			return;
+		}
+
+		p_h *=6.0;
+		p_h = ::fmod(p_h,6);
+		i = ::floor( p_h );
+
+		f = p_h - i;
+		p = p_v * ( 1 - p_s );
+		q = p_v * ( 1 - p_s * f );
+		t = p_v * ( 1 - p_s * ( 1 - f ) );
+
+		switch( i ) {
+			case 0: // Red is the dominant color
+				r = p_v;
+				g = t;
+				b = p;
+				break;
+			case 1: // Green is the dominant color
+				r = q;
+				g = p_v;
+				b = p;
+				break;
+			case 2:
+				r = p;
+				g = p_v;
+				b = t;
+				break;
+			case 3: // Blue is the dominant color
+				r = p;
+				g = q;
+				b = p_v;
+				break;
+			case 4:
+				r = t;
+				g = p;
+				b = p_v;
+				break;
+			default: // (5) Red is the dominant color
+				r = p_v;
+				g = p;
+				b = q;
+				break;
+		}
+	}
+
+	float& operator[](int idx) {
+		return components[idx];
+	}
+	const float& operator[](int idx) const {
+		return components[idx];
+	}
+
+	void invert()
+	{
+		r=1.0-r;
+		g=1.0-g;
+		b=1.0-b;
+	}
+
+	void contrast()
+	{
+		r=::fmod(r+0.5,1.0);
+		g=::fmod(g+0.5,1.0);
+		b=::fmod(b+0.5,1.0);
+	}
+	Color inverted() const
+	{
+		Color c=*this;
+		c.invert();
+		return c;
+	}
+	Color contrasted() const
+	{
+		Color c=*this;
+		c.contrast();
+		return c;
+	}
+
+	Color linear_interpolate(const Color& p_b, float p_t) const {
+
+		Color res=*this;
+
+		res.r+= (p_t * (p_b.r-r));
+		res.g+= (p_t * (p_b.g-g));
+		res.b+= (p_t * (p_b.b-b));
+		res.a+= (p_t * (p_b.a-a));
+
+		return res;
+	}
+
+	Color blend(const Color& p_over) const {
+
+
+		Color res;
+		float sa = 1.0 - p_over.a;
+		res.a = a*sa+p_over.a;
+		if (res.a==0) {
+			return Color(0,0,0,0);
+		} else {
+			res.r = (r*a*sa + p_over.r * p_over.a)/res.a;
+			res.g = (g*a*sa + p_over.g * p_over.a)/res.a;
+			res.b = (b*a*sa + p_over.b * p_over.a)/res.a;
+		}
+		return res;
+	}
+
+	Color to_linear() const {
+
+		return Color(
+			r<0.04045 ? r * (1.0 / 12.92) : ::pow((r + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+			g<0.04045 ? g * (1.0 / 12.92) : ::pow((g + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+			b<0.04045 ? b * (1.0 / 12.92) : ::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+			a
+		);
+	}
+
+	static Color hex(uint32_t p_hex)
+	{
+		float a = (p_hex&0xFF)/255.0;
+		p_hex>>=8;
+		float b = (p_hex&0xFF)/255.0;
+		p_hex>>=8;
+		float g = (p_hex&0xFF)/255.0;
+		p_hex>>=8;
+		float r = (p_hex&0xFF)/255.0;
+
+		return Color(r,g,b,a);
+	}
+
+	static Color html(const String& p_color)
+	{
+		String color = p_color;
+		if (color.length()==0)
+			return Color();
+		if (color[0]=='#')
+			color=color.substr(1,color.length()-1);
+
+		bool alpha=false;
+
+		if (color.length()==8) {
+			alpha=true;
+		} else if (color.length()==6) {
+			alpha=false;
+		} else {
+			// @Todo error reporting
+			// ERR_EXPLAIN("Invalid Color Code: "+p_color);
+			// ERR_FAIL_V(Color());
+			return Color();
+		}
+
+		int a=255;
+		if (alpha) {
+			a=_parse_col(color,0);
+			if (a<0) {
+				// @Todo error reporting
+				// ERR_EXPLAIN("Invalid Color Code: "+p_color);
+				// ERR_FAIL_V(Color());
+				return Color();
+			}
+		}
+
+		int from=alpha?2:0;
+
+		int r=_parse_col(color,from+0);
+		if (r<0) {
+			// @Todo error reporting
+			// ERR_EXPLAIN("Invalid Color Code: "+p_color);
+			// ERR_FAIL_V(Color());
+			return Color();
+		}
+		int g=_parse_col(color,from+2);
+		if (g<0) {
+			// @Todo error reporting
+			// ERR_EXPLAIN("Invalid Color Code: "+p_color);
+			// ERR_FAIL_V(Color());
+			return Color();
+		}
+		int b=_parse_col(color,from+4);
+		if (b<0) {
+			// @Todo error reporting
+			// ERR_EXPLAIN("Invalid Color Code: "+p_color);
+			// ERR_FAIL_V(Color());
+			return Color();
+		}
+
+		return Color(r/255.0,g/255.0,b/255.0,a/255.0);
+	}
+
+	static bool html_is_valid(const String& p_color)
+	{
+		String color = p_color;
+
+		if (color.length()==0)
+			return false;
+		if (color[0]=='#')
+			color=color.substr(1,color.length()-1);
+
+		bool alpha=false;
+
+		if (color.length()==8) {
+			alpha=true;
+		} else if (color.length()==6) {
+			alpha=false;
+		} else {
+			return false;
+		}
+
+		int a=255;
+		if (alpha) {
+			a=_parse_col(color,0);
+			if (a<0) {
+				return false;
+			}
+		}
+
+		int from=alpha?2:0;
+
+		int r=_parse_col(color,from+0);
+		if (r<0) {
+			return false;
+		}
+		int g=_parse_col(color,from+2);
+		if (g<0) {
+			return false;
+		}
+		int b=_parse_col(color,from+4);
+		if (b<0) {
+			return false;
+		}
+
+		return true;
+	}
+
+private:
+#ifndef CLAMP
+#define CLAMP(m_a,m_min,m_max) (((m_a)<(m_min))?(m_min):(((m_a)>(m_max))?m_max:m_a))
+#endif
+	static String _to_hex(float p_val) {
+
+		int v = p_val * 255;
+		v = CLAMP(v,0,255);
+		String ret;
+
+		for(int i=0;i<2;i++) {
+
+			wchar_t c[2]={0,0};
+			int lv = v&0xF;
+			if (lv<10)
+				c[0]='0'+lv;
+			else
+				c[0]='a'+lv-10;
+
+			v>>=4;
+			String cs=(const wchar_t*)c;
+			ret = cs + ret;
+		}
+
+		return ret;
+
+	}
+
+public:
+
+	String to_html(bool p_alpha=true) const
+	{
+		String txt;
+		txt+=_to_hex(r);
+		txt+=_to_hex(g);
+		txt+=_to_hex(b);
+		if (p_alpha)
+			txt=_to_hex(a)+txt;
+		return txt;
+	}
+
+	bool operator<(const Color& p_color) const; //used in set keys
+	operator String() const
+	{
+		return String(); // @Todo
+	}
+
+	/**
+	 * No construct parameters, r=0, g=0, b=0. a=255
+	 */
+	Color() {
+		r=0; g=0; b=0; a=1.0;
+	}
+
+	/**
+	 * RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
+	 */
+	Color(float p_r,float p_g,float p_b,float p_a=1.0) { r=p_r; g=p_g; b=p_b; a=p_a; }
+};
+
+bool Color::operator<(const Color& p_color) const {
+
+	if (r==p_color.r) {
+		if (g==p_color.g) {
+			if(b==p_color.b) {
+				return (a<p_color.a);
+			} else
+				return (b<p_color.b);
+		} else
+			return g<p_color.g;
+	} else
+		return r<p_color.r;
+
+}
+
+}
+
+#endif // COLOR_H