Blender V5.0
math_color_inline.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_base.h"
10#include "BLI_math_color.h"
11
12#include <cmath>
13
14#ifndef __MATH_COLOR_INLINE_C__
15# define __MATH_COLOR_INLINE_C__
16
17/******************************** Color Space ********************************/
18
19MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
20{
21 srgb_to_linearrgb_v3_v3(linear, srgb);
22 linear[3] = srgb[3];
23}
24
25MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4])
26{
27 linearrgb_to_srgb_v3_v3(srgb, linear);
28 srgb[3] = linear[3];
29}
30
31MINLINE void linearrgb_to_srgb_uchar3(unsigned char srgb[3], const float linear[3])
32{
33 float srgb_f[3];
34
35 linearrgb_to_srgb_v3_v3(srgb_f, linear);
36 unit_float_to_uchar_clamp_v3(srgb, srgb_f);
37}
38
39MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[4])
40{
41 float srgb_f[4];
42
43 linearrgb_to_srgb_v4(srgb_f, linear);
44 unit_float_to_uchar_clamp_v4(srgb, srgb_f);
45}
46
47/* predivide versions to work on associated/pre-multiplied alpha. if this should
48 * be done or not depends on the background the image will be composited over,
49 * ideally you would never do color space conversion on an image with alpha
50 * because it is ill defined */
51
52MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4])
53{
54 float alpha, inv_alpha;
55
56 if (srgb[3] == 1.0f || srgb[3] == 0.0f) {
57 alpha = 1.0f;
58 inv_alpha = 1.0f;
59 }
60 else {
61 alpha = srgb[3];
62 inv_alpha = 1.0f / alpha;
63 }
64
65 linear[0] = srgb[0] * inv_alpha;
66 linear[1] = srgb[1] * inv_alpha;
67 linear[2] = srgb[2] * inv_alpha;
68 linear[3] = srgb[3];
69 srgb_to_linearrgb_v3_v3(linear, linear);
70 linear[0] *= alpha;
71 linear[1] *= alpha;
72 linear[2] *= alpha;
73}
74
75MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4])
76{
77 float alpha, inv_alpha;
78
79 if (linear[3] == 1.0f || linear[3] == 0.0f) {
80 alpha = 1.0f;
81 inv_alpha = 1.0f;
82 }
83 else {
84 alpha = linear[3];
85 inv_alpha = 1.0f / alpha;
86 }
87
88 srgb[0] = linear[0] * inv_alpha;
89 srgb[1] = linear[1] * inv_alpha;
90 srgb[2] = linear[2] * inv_alpha;
91 srgb[3] = linear[3];
92 linearrgb_to_srgb_v3_v3(srgb, srgb);
93 srgb[0] *= alpha;
94 srgb[1] *= alpha;
95 srgb[2] *= alpha;
96}
97
98/* LUT accelerated conversions */
99
100extern float BLI_color_from_srgb_table[256];
101extern unsigned short BLI_color_to_srgb_table[0x10000];
102
103MINLINE unsigned short to_srgb_table_lookup(const float f)
104{
105
106 union {
107 float f;
108 unsigned short us[2];
109 } tmp;
110 tmp.f = f;
111 /* NOTE: this is endianness-sensitive. */
112 return BLI_color_to_srgb_table[tmp.us[1]];
113}
114
115MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4])
116{
117 srgb[0] = to_srgb_table_lookup(linear[0]);
118 srgb[1] = to_srgb_table_lookup(linear[1]);
119 srgb[2] = to_srgb_table_lookup(linear[2]);
120 srgb[3] = unit_float_to_ushort_clamp(linear[3]);
121}
122
123MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
124{
125 linear[0] = BLI_color_from_srgb_table[srgb[0]];
126 linear[1] = BLI_color_from_srgb_table[srgb[1]];
127 linear[2] = BLI_color_from_srgb_table[srgb[2]];
128 linear[3] = srgb[3] * (1.0f / 255.0f);
129}
130
131MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4])
132{
133 float fsrgb[4];
134 int i;
135
136 if (srgb[3] == 255 || srgb[3] == 0) {
137 srgb_to_linearrgb_uchar4(linear, srgb);
138 return;
139 }
140
141 for (i = 0; i < 4; i++) {
142 fsrgb[i] = srgb[i] * (1.0f / 255.0f);
143 }
144
145 srgb_to_linearrgb_predivide_v4(linear, fsrgb);
146}
147
148MINLINE void rgb_uchar_to_float(float r_col[3], const uchar col_ub[3])
149{
150 r_col[0] = float(col_ub[0]) * (1.0f / 255.0f);
151 r_col[1] = float(col_ub[1]) * (1.0f / 255.0f);
152 r_col[2] = float(col_ub[2]) * (1.0f / 255.0f);
153}
154
155MINLINE void rgba_uchar_to_float(float r_col[4], const uchar col_ub[4])
156{
157 r_col[0] = float(col_ub[0]) * (1.0f / 255.0f);
158 r_col[1] = float(col_ub[1]) * (1.0f / 255.0f);
159 r_col[2] = float(col_ub[2]) * (1.0f / 255.0f);
160 r_col[3] = float(col_ub[3]) * (1.0f / 255.0f);
161}
162
163MINLINE void rgb_float_to_uchar(uchar r_col[3], const float col_f[3])
164{
165 unit_float_to_uchar_clamp_v3(r_col, col_f);
166}
167
168MINLINE void rgba_float_to_uchar(uchar r_col[4], const float col_f[4])
169{
170 unit_float_to_uchar_clamp_v4(r_col, col_f);
171}
172
174 uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
175{
176 col[0] = r;
177 col[1] = g;
178 col[2] = b;
179 col[3] = a;
180}
181
183 float col[4], const float r, const float g, const float b, const float a)
184{
185 col[0] = r;
186 col[1] = g;
187 col[2] = b;
188 col[3] = a;
189}
190
192 uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
193{
194 if (col[3] == 0) {
195 col[0] = r;
196 col[1] = g;
197 col[2] = b;
198 col[3] = a;
199 }
200}
201
202MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
203{
204 r_col[0] = ((pack) >> 0) & 0xFF;
205 r_col[1] = ((pack) >> 8) & 0xFF;
206 r_col[2] = ((pack) >> 16) & 0xFF;
207}
208
209/* -------------------------------------------------------------------- */
217
218MINLINE float srgb_to_grayscale(const float rgb[3])
219{
220 /* Real values are:
221 * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
222 * according to: "Derivation of Basic Television Color Equations", RP 177-1993
223 *
224 * As this sums slightly above 1.0, the document recommends to use:
225 * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here. */
226 return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
227}
228
229MINLINE unsigned char srgb_to_grayscale_byte(const unsigned char rgb[3])
230{
231 /* The high precision values are used to calculate the rounded byte weights so they add up to
232 * 255: `54(R) + 182(G) + 19(B)` */
233 return (unsigned char)(((54 * (unsigned short)rgb[0]) + (182 * (unsigned short)rgb[1]) +
234 (19 * (unsigned short)rgb[2])) /
235 255);
236}
237
239
240MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
241 const unsigned char col_b[3],
242 const int limit)
243{
244 const int r = (int)col_a[0] - (int)col_b[0];
245 if (abs(r) < limit) {
246 const int g = (int)col_a[1] - (int)col_b[1];
247 if (abs(g) < limit) {
248 const int b = (int)col_a[2] - (int)col_b[2];
249 if (abs(b) < limit) {
250 return 1;
251 }
252 }
253 }
254
255 return 0;
256}
257
258/* 2D hash (iqint3) recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
259 * https://jcgt.org/published/0009/03/02/ */
260MINLINE float hash_iqint3_f(const uint32_t x, const uint32_t y)
261{
262 const uint32_t qx = 1103515245u * ((x >> 1u) ^ (y));
263 const uint32_t qy = 1103515245u * ((y >> 1u) ^ (x));
264 const uint32_t n = 1103515245u * ((qx) ^ (qy >> 3u));
265 return float(n) * (1.0f / float(0xffffffffu));
266}
267
269{
270 float v = hash_iqint3_f(x, y);
271 /* Convert uniform distribution into triangle-shaped distribution. Based on
272 * "remap_pdf_tri_unity" from https://www.shadertoy.com/view/WldSRf */
273 v = v * 2.0f - 1.0f;
274 v = signf(v) * (1.0f - sqrtf(1.0f - fabsf(v)));
275 return v;
276}
277
279 unsigned char b[3], const float f[3], float dither, int x, int y)
280{
281 float dither_value = dither_random_value(x, y) * 0.0033f * dither;
282
283 b[0] = unit_float_to_uchar_clamp(dither_value + f[0]);
284 b[1] = unit_float_to_uchar_clamp(dither_value + f[1]);
285 b[2] = unit_float_to_uchar_clamp(dither_value + f[2]);
286}
287
288/**************** Alpha Transformations *****************/
289
290MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
291{
292 if (premul[3] == 0.0f || premul[3] == 1.0f) {
293 straight[0] = premul[0];
294 straight[1] = premul[1];
295 straight[2] = premul[2];
296 straight[3] = premul[3];
297 }
298 else {
299 const float alpha_inv = 1.0f / premul[3];
300 straight[0] = premul[0] * alpha_inv;
301 straight[1] = premul[1] * alpha_inv;
302 straight[2] = premul[2] * alpha_inv;
303 straight[3] = premul[3];
304 }
305}
306
307MINLINE void premul_to_straight_v4(float color[4])
308{
309 premul_to_straight_v4_v4(color, color);
310}
311
312MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4])
313{
314 const float alpha = straight[3];
315 premul[0] = straight[0] * alpha;
316 premul[1] = straight[1] * alpha;
317 premul[2] = straight[2] * alpha;
318 premul[3] = straight[3];
319}
320
321MINLINE void straight_to_premul_v4(float color[4])
322{
323 straight_to_premul_v4_v4(color, color);
324}
325
326MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
327{
328 const float alpha = color[3] * (1.0f / 255.0f);
329 const float fac = alpha * (1.0f / 255.0f);
330
331 result[0] = color[0] * fac;
332 result[1] = color[1] * fac;
333 result[2] = color[2] * fac;
334 result[3] = alpha;
335}
336
337MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
338{
339 if (color[3] == 0.0f || color[3] == 1.0f) {
340 result[0] = unit_float_to_uchar_clamp(color[0]);
341 result[1] = unit_float_to_uchar_clamp(color[1]);
342 result[2] = unit_float_to_uchar_clamp(color[2]);
343 result[3] = unit_float_to_uchar_clamp(color[3]);
344 }
345 else {
346 const float alpha_inv = 1.0f / color[3];
347
348 /* hopefully this would be optimized */
349 result[0] = unit_float_to_uchar_clamp(color[0] * alpha_inv);
350 result[1] = unit_float_to_uchar_clamp(color[1] * alpha_inv);
351 result[2] = unit_float_to_uchar_clamp(color[2] * alpha_inv);
352 result[3] = unit_float_to_uchar_clamp(color[3]);
353 }
354}
355
356#endif /* !__MATH_COLOR_INLINE_C__ */
MINLINE float signf(float f)
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
#define MINLINE
unsigned char uchar
ATTR_WARN_UNUSED_RESULT const BMVert * v
nullptr float
uint col
#define abs
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
#define unit_float_to_uchar_clamp_v4(v1, v2)
MINLINE unsigned short unit_float_to_ushort_clamp(float val)
#define unit_float_to_uchar_clamp_v3(v1, v2)
ushort BLI_color_to_srgb_table[0x10000]
float BLI_color_from_srgb_table[256]
MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4])
MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4])
MINLINE void rgba_uchar_args_set(uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
MINLINE void premul_to_straight_v4(float color[4])
MINLINE void straight_to_premul_v4(float color[4])
MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a)
MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4])
MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4])
MINLINE float dither_random_value(int x, int y)
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
MINLINE float hash_iqint3_f(const uint32_t x, const uint32_t y)
MINLINE void rgb_uchar_to_float(float r_col[3], const uchar col_ub[3])
MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit)
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float dither, int x, int y)
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[4])
MINLINE void rgba_float_to_uchar(uchar r_col[4], const float col_f[4])
MINLINE void rgba_uchar_args_test_set(uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
MINLINE unsigned char srgb_to_grayscale_byte(const unsigned char rgb[3])
MINLINE unsigned short to_srgb_table_lookup(const float f)
MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4])
MINLINE void linearrgb_to_srgb_uchar3(unsigned char srgb[3], const float linear[3])
MINLINE void rgba_uchar_to_float(float r_col[4], const uchar col_ub[4])
MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4])
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
MINLINE float srgb_to_grayscale(const float rgb[3])
MINLINE void rgb_float_to_uchar(uchar r_col[3], const float col_f[3])
#define fabsf
#define sqrtf
i
Definition text_draw.cc:230