Blender V4.5
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# ifdef __BIG_ENDIAN__
112 return BLI_color_to_srgb_table[tmp.us[0]];
113# else
114 return BLI_color_to_srgb_table[tmp.us[1]];
115# endif
116}
117
118MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4])
119{
120 srgb[0] = to_srgb_table_lookup(linear[0]);
121 srgb[1] = to_srgb_table_lookup(linear[1]);
122 srgb[2] = to_srgb_table_lookup(linear[2]);
123 srgb[3] = unit_float_to_ushort_clamp(linear[3]);
124}
125
126MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
127{
128 linear[0] = BLI_color_from_srgb_table[srgb[0]];
129 linear[1] = BLI_color_from_srgb_table[srgb[1]];
130 linear[2] = BLI_color_from_srgb_table[srgb[2]];
131 linear[3] = srgb[3] * (1.0f / 255.0f);
132}
133
134MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4])
135{
136 float fsrgb[4];
137 int i;
138
139 if (srgb[3] == 255 || srgb[3] == 0) {
140 srgb_to_linearrgb_uchar4(linear, srgb);
141 return;
142 }
143
144 for (i = 0; i < 4; i++) {
145 fsrgb[i] = srgb[i] * (1.0f / 255.0f);
146 }
147
148 srgb_to_linearrgb_predivide_v4(linear, fsrgb);
149}
150
152 uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
153{
154 col[0] = r;
155 col[1] = g;
156 col[2] = b;
157 col[3] = a;
158}
159
161 float col[4], const float r, const float g, const float b, const float a)
162{
163 col[0] = r;
164 col[1] = g;
165 col[2] = b;
166 col[3] = a;
167}
168
170 uchar col[4], const uchar r, const uchar g, const uchar b, const uchar a)
171{
172 if (col[3] == 0) {
173 col[0] = r;
174 col[1] = g;
175 col[2] = b;
176 col[3] = a;
177 }
178}
179
180MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
181{
182 r_col[0] = ((pack) >> 0) & 0xFF;
183 r_col[1] = ((pack) >> 8) & 0xFF;
184 r_col[2] = ((pack) >> 16) & 0xFF;
185}
186
187/* -------------------------------------------------------------------- */
195
196MINLINE float srgb_to_grayscale(const float rgb[3])
197{
198 /* Real values are:
199 * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
200 * according to: "Derivation of Basic Television Color Equations", RP 177-1993
201 *
202 * As this sums slightly above 1.0, the document recommends to use:
203 * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here. */
204 return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
205}
206
207MINLINE unsigned char srgb_to_grayscale_byte(const unsigned char rgb[3])
208{
209 /* The high precision values are used to calculate the rounded byte weights so they add up to
210 * 255: `54(R) + 182(G) + 19(B)` */
211 return (unsigned char)(((54 * (unsigned short)rgb[0]) + (182 * (unsigned short)rgb[1]) +
212 (19 * (unsigned short)rgb[2])) /
213 255);
214}
215
217
218MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
219 const unsigned char col_b[3],
220 const int limit)
221{
222 const int r = (int)col_a[0] - (int)col_b[0];
223 if (abs(r) < limit) {
224 const int g = (int)col_a[1] - (int)col_b[1];
225 if (abs(g) < limit) {
226 const int b = (int)col_a[2] - (int)col_b[2];
227 if (abs(b) < limit) {
228 return 1;
229 }
230 }
231 }
232
233 return 0;
234}
235
236/* 2D hash (iqint3) recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
237 * https://jcgt.org/published/0009/03/02/ */
238MINLINE float hash_iqint3_f(const uint32_t x, const uint32_t y)
239{
240 const uint32_t qx = 1103515245u * ((x >> 1u) ^ (y));
241 const uint32_t qy = 1103515245u * ((y >> 1u) ^ (x));
242 const uint32_t n = 1103515245u * ((qx) ^ (qy >> 3u));
243 return float(n) * (1.0f / float(0xffffffffu));
244}
245
247{
248 float v = hash_iqint3_f(x, y);
249 /* Convert uniform distribution into triangle-shaped distribution. Based on
250 * "remap_pdf_tri_unity" from https://www.shadertoy.com/view/WldSRf */
251 v = v * 2.0f - 1.0f;
252 v = signf(v) * (1.0f - sqrtf(1.0f - fabsf(v)));
253 return v;
254}
255
257 unsigned char b[3], const float f[3], float dither, int x, int y)
258{
259 float dither_value = dither_random_value(x, y) * 0.0033f * dither;
260
261 b[0] = unit_float_to_uchar_clamp(dither_value + f[0]);
262 b[1] = unit_float_to_uchar_clamp(dither_value + f[1]);
263 b[2] = unit_float_to_uchar_clamp(dither_value + f[2]);
264}
265
266/**************** Alpha Transformations *****************/
267
268MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
269{
270 if (premul[3] == 0.0f || premul[3] == 1.0f) {
271 straight[0] = premul[0];
272 straight[1] = premul[1];
273 straight[2] = premul[2];
274 straight[3] = premul[3];
275 }
276 else {
277 const float alpha_inv = 1.0f / premul[3];
278 straight[0] = premul[0] * alpha_inv;
279 straight[1] = premul[1] * alpha_inv;
280 straight[2] = premul[2] * alpha_inv;
281 straight[3] = premul[3];
282 }
283}
284
285MINLINE void premul_to_straight_v4(float color[4])
286{
287 premul_to_straight_v4_v4(color, color);
288}
289
290MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4])
291{
292 const float alpha = straight[3];
293 premul[0] = straight[0] * alpha;
294 premul[1] = straight[1] * alpha;
295 premul[2] = straight[2] * alpha;
296 premul[3] = straight[3];
297}
298
299MINLINE void straight_to_premul_v4(float color[4])
300{
301 straight_to_premul_v4_v4(color, color);
302}
303
304MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
305{
306 const float alpha = color[3] * (1.0f / 255.0f);
307 const float fac = alpha * (1.0f / 255.0f);
308
309 result[0] = color[0] * fac;
310 result[1] = color[1] * fac;
311 result[2] = color[2] * fac;
312 result[3] = alpha;
313}
314
315MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
316{
317 if (color[3] == 0.0f || color[3] == 1.0f) {
318 result[0] = unit_float_to_uchar_clamp(color[0]);
319 result[1] = unit_float_to_uchar_clamp(color[1]);
320 result[2] = unit_float_to_uchar_clamp(color[2]);
321 result[3] = unit_float_to_uchar_clamp(color[3]);
322 }
323 else {
324 const float alpha_inv = 1.0f / color[3];
325
326 /* hopefully this would be optimized */
327 result[0] = unit_float_to_uchar_clamp(color[0] * alpha_inv);
328 result[1] = unit_float_to_uchar_clamp(color[1] * alpha_inv);
329 result[2] = unit_float_to_uchar_clamp(color[2] * alpha_inv);
330 result[3] = unit_float_to_uchar_clamp(color[3]);
331 }
332}
333
334#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
#define fabsf(x)
#define sqrtf(x)
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 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_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 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])
i
Definition text_draw.cc:230