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