1 /*
2  * This software is licensed under the terms of the MIT License.
3  * See COPYING for further information.
4  * ---
5  * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6  * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7  */
8 
9 #include "taisei.h"
10 
11 #include "color.h"
12 
13 #define COLOR_OP(c1, op, c2) do { \
14 	(c1)->r = (c1)->r op (c2)->r; \
15 	(c1)->g = (c1)->g op (c2)->g; \
16 	(c1)->b = (c1)->b op (c2)->b; \
17 	(c1)->a = (c1)->a op (c2)->a; \
18 } while(0);
19 
color_copy(Color * dst,const Color * src)20 Color* color_copy(Color *dst, const Color *src) {
21 	*dst = *src;
22 	return dst;
23 }
24 
color_add(Color * clr,const Color * clr2)25 Color* color_add(Color *clr, const Color *clr2) {
26 	COLOR_OP(clr, +, clr2);
27 	return clr;
28 }
29 
color_sub(Color * clr,const Color * clr2)30 Color* color_sub(Color *clr, const Color *clr2) {
31 	COLOR_OP(clr, -, clr2);
32 	return clr;
33 }
34 
color_mul(Color * clr,const Color * clr2)35 Color* color_mul(Color *clr, const Color *clr2) {
36 	COLOR_OP(clr, *, clr2);
37 	return clr;
38 }
39 
color_mul_alpha(Color * clr)40 Color* color_mul_alpha(Color *clr) {
41 	clr->r *= clr->a;
42 	clr->g *= clr->a;
43 	clr->b *= clr->a;
44 	return clr;
45 }
46 
color_mul_scalar(Color * clr,float scalar)47 Color* color_mul_scalar(Color *clr, float scalar) {
48 	clr->r *= scalar;
49 	clr->g *= scalar;
50 	clr->b *= scalar;
51 	clr->a *= scalar;
52 	return clr;
53 }
54 
color_div(Color * clr,const Color * clr2)55 Color* color_div(Color *clr, const Color *clr2) {
56 	COLOR_OP(clr, /, clr2);
57 	return clr;
58 }
59 
color_div_alpha(Color * clr)60 Color* color_div_alpha(Color *clr) {
61 	if(clr->a != 0) {
62 		clr->r /= clr->a;
63 		clr->g /= clr->a;
64 		clr->b /= clr->a;
65 	}
66 
67 	return clr;
68 }
69 
color_div_scalar(Color * clr,float scalar)70 Color* color_div_scalar(Color *clr, float scalar) {
71 	clr->r /= scalar;
72 	clr->g /= scalar;
73 	clr->b /= scalar;
74 	clr->a /= scalar;
75 	return clr;
76 }
77 
color_lerp(Color * clr,const Color * clr2,float a)78 Color* color_lerp(Color *clr, const Color *clr2, float a) {
79 	float ia = 1 - a;
80 	clr->r = clr->r * ia + clr2->r * a;
81 	clr->g = clr->g * ia + clr2->g * a;
82 	clr->b = clr->b * ia + clr2->b * a;
83 	clr->a = clr->a * ia + clr2->a * a;
84 	return clr;
85 }
86 
color_approach(Color * clr,const Color * clr2,float delta)87 Color* color_approach(Color *clr, const Color *clr2, float delta) {
88 	clr->r += (clr2->r - clr->r) * delta;
89 	clr->g += (clr2->g - clr->g) * delta;
90 	clr->b += (clr2->b - clr->b) * delta;
91 	clr->a += (clr2->a - clr->a) * delta;
92 	return clr;
93 }
94 
hue_to_rgb(float v1,float v2,float vH)95 static float hue_to_rgb(float v1, float v2, float vH) {
96 	if(vH < 0) {
97 		vH += 1;
98 	}
99 
100 	if(vH > 1) {
101 		vH -= 1;
102 	}
103 
104 	if((6 * vH) < 1) {
105 		return (v1 + (v2 - v1) * 6 * vH);
106 	}
107 
108 	if((2 * vH) < 1) {
109 		return v2;
110 	}
111 
112 	if((3 * vH) < 2) {
113 		return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
114 	}
115 
116 	return v1;
117 }
118 
color_hsla(Color * clr,float h,float s,float l,float a)119 Color* color_hsla(Color *clr, float h, float s, float l, float a) {
120 	if(s == 0) {
121 		clr->r = clr->g = clr->b = l;
122 	} else {
123 		float v1, v2;
124 		h = fmod(h, 1.0);
125 
126 		if(l < 0.5) {
127 			v2 = l * (1.0 + s);
128 		} else {
129 			v2 = l + s - s * l;
130 		}
131 
132 		v1 = 2.0 * l - v2;
133 
134 		clr->r = hue_to_rgb(v1, v2, h + (1.0/3.0));
135 		clr->g = hue_to_rgb(v1, v2, h);
136 		clr->b = hue_to_rgb(v1, v2, h - (1.0/3.0));
137 	}
138 
139 	clr->a = a;
140 	return clr;
141 }
142 
color_get_hsl(const Color * c,float * out_h,float * out_s,float * out_l)143 void color_get_hsl(const Color *c, float *out_h, float *out_s, float *out_l) {
144 	float r = clamp(c->r, 0, 1);
145 	float g = clamp(c->g, 0, 1);
146 	float b = clamp(c->b, 0, 1);
147 
148 	float maxv = max(max(r, g), b);
149 	float minv = min(min(r, g), b);
150 	float h = 0, s = 0, d = maxv - minv, l = (maxv + minv) / 2;
151 
152 	if(maxv != minv) {
153 		s = l > 0.5 ? d / (2 - maxv - minv) : d / (maxv + minv);
154 		if(maxv == r) {
155 			h = (g - b) / d + (g < b ? 6 : 0);
156 		} else if(maxv == g) {
157 			h = (b - r) / d + 2;
158 		} else if(maxv == b) {
159 			h = (r - g) / d + 4;
160 		}
161 		h /= 6;
162 	}
163 
164 	if(out_h) *out_h = h;
165 	if(out_s) *out_s = s;
166 	if(out_l) *out_l = l;
167 }
168 
color_set_opacity(Color * clr,float opacity)169 Color* color_set_opacity(Color *clr, float opacity) {
170 	// FIXME: is this correct?
171 
172 	if(clr->a != 0) {
173 		opacity /= clr->a;
174 	}
175 
176 	color_mul_scalar(clr, opacity);
177 	return clr;
178 }
179 
color_equals(const Color * clr,const Color * clr2)180 bool color_equals(const Color *clr, const Color *clr2) {
181 	return (
182 		clr->r == clr2->r &&
183 		clr->g == clr2->g &&
184 		clr->b == clr2->b &&
185 		clr->a == clr2->a
186 	);
187 }
188 
color_str(const Color * clr)189 char* color_str(const Color *clr) {
190 	return strfmt(
191 		"RGBA(%f, %f, %f, %f) at %p",
192 		clr->r,
193 		clr->g,
194 		clr->b,
195 		clr->a,
196 		(void*)clr
197 	);
198 }
199