Blender V5.0
color.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "util/math.h"
8#include "util/types.h"
9
11
13{
14 return ((val <= 0.0f) ?
15 0 :
16 ((val > (1.0f - 0.5f / 255.0f)) ? 255 : (uchar)((255.0f * val) + 0.5f))); // NOLINT
17}
18
20{
21 return val * (1.0f / 255.0f);
22}
23
25{
26 uchar r;
27 uchar g;
28 uchar b;
29
30 r = float_to_byte(c.x);
31 g = float_to_byte(c.y);
32 b = float_to_byte(c.z);
33
34 return make_uchar4(r, g, b, 0);
35}
36
38{
39 uchar r;
40 uchar g;
41 uchar b;
42 uchar a;
43
44 r = float_to_byte(c.x);
45 g = float_to_byte(c.y);
46 b = float_to_byte(c.z);
47 a = float_to_byte(c.w);
48
49 return make_uchar4(r, g, b, a);
50}
51
53{
54 return make_float3(c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f));
55}
56
58{
59 return make_float4(
60 c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f), c.w * (1.0f / 255.0f));
61}
62
63ccl_device float color_srgb_to_linear(const float c)
64{
65 if (c < 0.04045f) {
66 return (c < 0.0f) ? 0.0f : c * (1.0f / 12.92f);
67 }
68 return powf((c + 0.055f) * (1.0f / 1.055f), 2.4f);
69}
70
71ccl_device float color_linear_to_srgb(const float c)
72{
73 if (c < 0.0031308f) {
74 return (c < 0.0f) ? 0.0f : c * 12.92f;
75 }
76 return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
77}
78
80{
81 float cmax;
82 float cmin;
83 float h;
84 float s;
85 float v;
86 float cdelta;
87 float3 c;
88
89 cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
90 cmin = min(rgb.x, min(rgb.y, rgb.z));
91 cdelta = cmax - cmin;
92
93 v = cmax;
94
95 if (cmax != 0.0f) {
96 s = cdelta / cmax;
97 }
98 else {
99 s = 0.0f;
100 h = 0.0f;
101 }
102
103 if (s != 0.0f) {
104 const float3 cmax3 = make_float3(cmax, cmax, cmax);
105 c = (cmax3 - rgb) / cdelta;
106
107 if (rgb.x == cmax) {
108 h = c.z - c.y;
109 }
110 else if (rgb.y == cmax) {
111 h = 2.0f + c.x - c.z;
112 }
113 else {
114 h = 4.0f + c.y - c.x;
115 }
116
117 h /= 6.0f;
118
119 if (h < 0.0f) {
120 h += 1.0f;
121 }
122 }
123 else {
124 h = 0.0f;
125 }
126
127 return make_float3(h, s, v);
128}
129
131{
132 float i;
133 float f;
134 float p;
135 float q;
136 float t;
137 float h;
138 float s;
139 float v;
140 float3 rgb;
141
142 h = hsv.x;
143 s = hsv.y;
144 v = hsv.z;
145
146 if (s != 0.0f) {
147 if (h == 1.0f) {
148 h = 0.0f;
149 }
150
151 h *= 6.0f;
152 i = floorf(h);
153 f = h - i;
154 rgb = make_float3(f, f, f);
155 p = v * (1.0f - s);
156 q = v * (1.0f - (s * f));
157 t = v * (1.0f - (s * (1.0f - f)));
158
159 if (i == 0.0f) {
160 rgb = make_float3(v, t, p);
161 }
162 else if (i == 1.0f) {
163 rgb = make_float3(q, v, p);
164 }
165 else if (i == 2.0f) {
166 rgb = make_float3(p, v, t);
167 }
168 else if (i == 3.0f) {
169 rgb = make_float3(p, q, v);
170 }
171 else if (i == 4.0f) {
172 rgb = make_float3(t, p, v);
173 }
174 else {
175 rgb = make_float3(v, p, q);
176 }
177 }
178 else {
179 rgb = make_float3(v, v, v);
180 }
181
182 return rgb;
183}
184
186{
187 float cmax;
188 float cmin;
189 float h;
190 float s;
191 float l;
192
193 cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
194 cmin = min(rgb.x, min(rgb.y, rgb.z));
195 l = min(1.0f, (cmax + cmin) / 2.0f);
196
197 if (cmax == cmin) {
198 h = s = 0.0f; /* achromatic */
199 }
200 else {
201 const float cdelta = cmax - cmin;
202 s = l > 0.5f ? cdelta / (2.0f - cmax - cmin) : cdelta / (cmax + cmin);
203 if (cmax == rgb.x) {
204 h = (rgb.y - rgb.z) / cdelta + (rgb.y < rgb.z ? 6.0f : 0.0f);
205 }
206 else if (cmax == rgb.y) {
207 h = (rgb.z - rgb.x) / cdelta + 2.0f;
208 }
209 else {
210 h = (rgb.x - rgb.y) / cdelta + 4.0f;
211 }
212 }
213 h /= 6.0f;
214
215 return make_float3(h, s, l);
216}
217
219{
220 float nr;
221 float ng;
222 float nb;
223 float chroma;
224 float h;
225 float s;
226 float l;
227
228 h = hsl.x;
229 s = hsl.y;
230 l = hsl.z;
231
232 nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
233 ng = 2.0f - fabsf(h * 6.0f - 2.0f);
234 nb = 2.0f - fabsf(h * 6.0f - 4.0f);
235
236 nr = clamp(nr, 0.0f, 1.0f);
237 nb = clamp(nb, 0.0f, 1.0f);
238 ng = clamp(ng, 0.0f, 1.0f);
239
240 chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
241
242 return make_float3((nr - 0.5f) * chroma + l, (ng - 0.5f) * chroma + l, (nb - 0.5f) * chroma + l);
243}
244
245ccl_device float3 xyY_to_xyz(const float x, const float y, float Y)
246{
247 float X;
248 float Z;
249
250 if (y != 0.0f) {
251 X = (x / y) * Y;
252 }
253 else {
254 X = 0.0f;
255 }
256
257 if (y != 0.0f && Y != 0.0f) {
258 Z = (1.0f - x - y) / y * Y;
259 }
260 else {
261 Z = 0.0f;
262 }
263
264 return make_float3(X, Y, Z);
265}
266
267#ifdef __KERNEL_SSE2__
268/*
269 * Calculate initial guess for arg^exp based on float representation
270 * This method gives a constant bias,
271 * which can be easily compensated by multiplication with bias_coeff.
272 * Gives better results for exponents near 1 (e. g. 4/5).
273 * exp = exponent, encoded as uint32_t
274 * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as uint32_t
275 */
276template<unsigned exp, unsigned e2coeff> ccl_device_inline float4 fastpow_sse2(const float4 &arg)
277{
278 float4 ret = arg * cast(make_int4(e2coeff));
280 ret = ret * cast(make_int4(exp));
281 ret = cast(make_int4(ret));
282 return ret;
283}
284
285/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
286ccl_device_inline float4 improve_5throot_solution_sse2(const float4 &old_result, const float4 &x)
287{
288 const float4 approx2 = old_result * old_result;
289 const float4 approx4 = approx2 * approx2;
290 const float4 t = x / approx4;
291 const float4 summ = madd(make_float4(4.0f), old_result, t);
292 return summ * make_float4(1.0f / 5.0f);
293}
294
295/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
296ccl_device_inline float4 fastpow24_sse2(const float4 &arg)
297{
298 /* `max`, `avg` and |avg| errors were calculated in GCC without FMA instructions.
299 * The final precision should be better than `powf` in GLIBC. */
300
301 /* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
302 /* 0x3F4CCCCD = 4/5 */
303 /* 0x4F55A7FB = 2^(127/(4/5) - 127) * 0.994^(1/(4/5)) */
304 float4 x = fastpow_sse2<0x3F4CCCCD, 0x4F55A7FB>(
305 arg); // error max = 0.17 avg = 0.0018 |avg| = 0.05
306 const float4 arg2 = arg * arg;
307 const float4 arg4 = arg2 * arg2;
308
309 /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
310 x = improve_5throot_solution_sse2(x, arg4);
311 /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
312 x = improve_5throot_solution_sse2(x, arg4);
313 /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
314 x = improve_5throot_solution_sse2(x, arg4);
315
316 return x * (x * x);
317}
318
319ccl_device float4 color_srgb_to_linear_sse2(const float4 &c)
320{
321 const int4 cmp = c < make_float4(0.04045f);
322 const float4 lt = max(c * make_float4(1.0f / 12.92f), make_float4(0.0f));
323 const float4 gtebase = (c + make_float4(0.055f)) * make_float4(1.0f / 1.055f); /* fma */
324 const float4 gte = fastpow24_sse2(gtebase);
325 return select(cmp, lt, gte);
326}
327#endif /* __KERNEL_SSE2__ */
328
334
340
346
348{
349#ifdef __KERNEL_SSE2__
350 float4 r = c;
351 r = color_srgb_to_linear_sse2(r);
352 r.w = c.w;
353 return r;
354#else
355 return make_float4(
357#endif
358}
359
361{
362 color += one_float3();
363 if (variance) {
364 *variance *= sqr(one_float3() / color);
365 }
366 return log(color);
367}
368
370{
371 return exp(color) - one_float3();
372}
373
374/* Color division */
375
377{
379 GET_SPECTRUM_CHANNEL(a, i) = (GET_SPECTRUM_CHANNEL(a, i) != 0.0f) ?
380 1.0f / GET_SPECTRUM_CHANNEL(a, i) :
381 0.0f;
382 }
383
384 return a;
385}
386
387/* Returns `a/b`, and replace the channel value with `fallback` if `b == 0`. */
389{
391 GET_SPECTRUM_CHANNEL(a, i) = (GET_SPECTRUM_CHANNEL(b, i) != 0.0f) ?
393 fallback;
394 }
395
396 return a;
397}
398
400{
401 float x;
402 float y;
403 float z;
404
405 x = (b.x != 0.0f) ? a.x / b.x : 0.0f;
406 y = (b.y != 0.0f) ? a.y / b.y : 0.0f;
407 z = (b.z != 0.0f) ? a.z / b.z : 0.0f;
408
409 /* try to get gray even if b is zero */
410 if (b.x == 0.0f) {
411 if (b.y == 0.0f) {
412 x = z;
413 y = z;
414 }
415 else if (b.z == 0.0f) {
416 x = y;
417 z = y;
418 }
419 else {
420 x = 0.5f * (y + z);
421 }
422 }
423 else if (b.y == 0.0f) {
424 if (b.z == 0.0f) {
425 y = x;
426 z = x;
427 }
428 else {
429 y = 0.5f * (x + z);
430 }
431 }
432 else if (b.z == 0.0f) {
433 z = 0.5f * (x + y);
434 }
435
436 return make_float3(x, y, z);
437}
438
unsigned char uchar
#define X
#define Z
#define Y
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
ccl_device_inline float4 color_uchar4_to_float4(const uchar4 c)
Definition color.h:57
ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b, const float fallback=0.0f)
Definition color.h:388
ccl_device float3 xyY_to_xyz(const float x, const float y, float Y)
Definition color.h:245
ccl_device float byte_to_float(const uchar val)
Definition color.h:19
ccl_device float3 color_highlight_compress(float3 color, ccl_private float3 *variance)
Definition color.h:360
ccl_device float3 hsv_to_rgb(const float3 hsv)
Definition color.h:130
ccl_device_inline Spectrum safe_invert_color(Spectrum a)
Definition color.h:376
ccl_device float3 color_linear_to_srgb_v3(const float3 c)
Definition color.h:335
CCL_NAMESPACE_BEGIN ccl_device uchar float_to_byte(const float val)
Definition color.h:12
ccl_device_inline float3 safe_divide_even_color(const float3 a, const float3 b)
Definition color.h:399
ccl_device float color_srgb_to_linear(const float c)
Definition color.h:63
ccl_device float4 color_srgb_to_linear_v4(const float4 c)
Definition color.h:347
ccl_device float3 color_highlight_uncompress(const float3 color)
Definition color.h:369
ccl_device uchar4 color_float_to_byte(const float3 c)
Definition color.h:24
ccl_device float3 color_srgb_to_linear_v3(const float3 c)
Definition color.h:329
ccl_device_inline float3 color_byte_to_float(const uchar4 c)
Definition color.h:52
ccl_device uchar4 color_float4_to_uchar4(const float4 c)
Definition color.h:37
ccl_device float4 color_linear_to_srgb_v4(const float4 c)
Definition color.h:341
ccl_device float3 rgb_to_hsl(const float3 rgb)
Definition color.h:185
ccl_device float3 rgb_to_hsv(const float3 rgb)
Definition color.h:79
ccl_device float color_linear_to_srgb(const float c)
Definition color.h:71
ccl_device float3 hsl_to_rgb(const float3 hsl)
Definition color.h:218
#define ccl_private
#define ccl_device_inline
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
#define powf(x, y)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline uchar4 make_uchar4(const uchar x, const uchar y, const uchar z, const uchar w)
ccl_device_forceinline int4 make_int4(const int x, const int y, const int z, const int w)
#define cast
#define log
#define exp
#define select(A, B, C)
constexpr T clamp(T, U, U) RET
CCL_NAMESPACE_BEGIN ccl_device_inline float madd(const float a, const float b, const float c)
Definition math_fast.h:35
ccl_device_inline float3 one_float3()
Definition math_float3.h:26
return ret
#define sqr
#define floorf
#define fabsf
#define ccl_device
#define fmaxf
#define make_float4
#define min(a, b)
Definition sort.cc:36
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
float y
Definition sky_math.h:225
float z
Definition sky_math.h:225
float x
Definition sky_math.h:225
float w
Definition sky_math.h:225
uchar z
uchar w
uchar x
uchar y
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
float3 Spectrum