Fix part of #34233: bad alpha blending for 2D image painting. This is a very
[blender.git] / source / blender / blenlib / intern / math_color_blend_inline.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: some of this file.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  * */
25
26 /** \file blender/blenlib/intern/math_color_inline.c
27  *  \ingroup bli
28  */
29
30
31 #include "BLI_math_base.h"
32 #include "BLI_math_color.h"
33 #include "BLI_utildefines.h"
34
35 #ifndef __MATH_COLOR_BLEND_INLINE_C__
36 #define __MATH_COLOR_BLEND_INLINE_C__
37
38 /***************************** Color Blending ********************************
39  *
40  * - byte colors are assumed to be straight alpha
41  * - byte colors uses to do >>8 (same as /256) but actually should do /255,
42  *   otherwise get quick darkening due to rounding
43  * - divide_round_i is also used to avoid darkening due to integers always
44  *   rounding down
45  * - float colors are assumed to be premultiplied alpha
46  */
47
48 /* straight alpha byte blending modes */
49
50 MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
51 {
52         if (src2[3] != 0) {
53                 /* straight over operation */
54                 const int t = src2[3];
55                 const int mt = 255 - t;
56                 int tmp[4];
57
58                 tmp[0] = (mt * src1[3] * src1[0]) + (t * 255 * src2[0]);
59                 tmp[1] = (mt * src1[3] * src1[1]) + (t * 255 * src2[1]);
60                 tmp[2] = (mt * src1[3] * src1[2]) + (t * 255 * src2[2]);
61                 tmp[3] = (mt * src1[3]) + (t * 255);
62
63                 dst[0] = divide_round_i(tmp[0], tmp[3]);
64                 dst[1] = divide_round_i(tmp[1], tmp[3]);
65                 dst[2] = divide_round_i(tmp[2], tmp[3]);
66                 dst[3] = divide_round_i(tmp[3], 255);
67         }
68         else {
69                 /* no op */
70                 dst[0] = src1[0];
71                 dst[1] = src1[1];
72                 dst[2] = src1[2];
73                 dst[3] = src1[3];
74         }
75 }
76
77 MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
78 {
79         if (src2[3] != 0) {
80                 /* straight add operation */
81                 const int t = src2[3];
82                 int tmp[3];
83
84                 tmp[0] = (src1[0] * 255) + (src2[0] * t);
85                 tmp[1] = (src1[1] * 255) + (src2[1] * t);
86                 tmp[2] = (src1[2] * 255) + (src2[2] * t);
87
88                 dst[0] = min_ii(divide_round_i(tmp[0], 255), 255);
89                 dst[1] = min_ii(divide_round_i(tmp[1], 255), 255);
90                 dst[2] = min_ii(divide_round_i(tmp[2], 255), 255);
91                 dst[3] = src1[3];
92         }
93         else {
94                 /* no op */
95                 dst[0] = src1[0];
96                 dst[1] = src1[1];
97                 dst[2] = src1[2];
98                 dst[3] = src1[3];
99         }
100 }
101
102 MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
103 {
104         if (src2[3] != 0) {
105                 /* straight sub operation */
106                 const int t = src2[3];
107                 int tmp[3];
108
109                 tmp[0] = (src1[0] * 255) - (src2[0] * t);
110                 tmp[1] = (src1[1] * 255) - (src2[1] * t);
111                 tmp[2] = (src1[2] * 255) - (src2[2] * t);
112
113                 dst[0] = max_ii(divide_round_i(tmp[0], 255), 0);
114                 dst[1] = max_ii(divide_round_i(tmp[1], 255), 0);
115                 dst[2] = max_ii(divide_round_i(tmp[2], 255), 0);
116                 dst[3] = src1[3];
117         }
118         else {
119                 /* no op */
120                 dst[0] = src1[0];
121                 dst[1] = src1[1];
122                 dst[2] = src1[2];
123                 dst[3] = src1[3];
124         }
125 }
126
127 MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
128 {
129         if (src2[3] != 0) {
130                 /* straight multiply operation */
131                 const int t = src2[3];
132                 const int mt = 255 - t;
133                 int tmp[3];
134
135                 tmp[0] = (mt * src1[0] * 255) + (t * src1[0] * src2[0]);
136                 tmp[1] = (mt * src1[1] * 255) + (t * src1[1] * src2[1]);
137                 tmp[2] = (mt * src1[2] * 255) + (t * src1[2] * src2[2]);
138
139                 dst[0] = divide_round_i(tmp[0], 255 * 255);
140                 dst[1] = divide_round_i(tmp[1], 255 * 255);
141                 dst[2] = divide_round_i(tmp[2], 255 * 255);
142                 dst[3] = src1[3];
143         }
144         else {
145                 /* no op */
146                 dst[0] = src1[0];
147                 dst[1] = src1[1];
148                 dst[2] = src1[2];
149                 dst[3] = src1[3];
150         }
151 }
152
153 MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
154 {
155         if (src2[3] != 0) {
156                 /* straight lighten operation */
157                 const int t = src2[3];
158                 const int mt = 255 - t;
159                 int tmp[3];
160
161                 tmp[0] = (mt * src1[0]) + (t * max_ii(src1[0], src2[0]));
162                 tmp[1] = (mt * src1[1]) + (t * max_ii(src1[1], src2[1]));
163                 tmp[2] = (mt * src1[2]) + (t * max_ii(src1[2], src2[2]));
164
165                 dst[0] = divide_round_i(tmp[0], 255);
166                 dst[1] = divide_round_i(tmp[1], 255);
167                 dst[2] = divide_round_i(tmp[2], 255);
168                 dst[3] = src1[3];
169         }
170         else {
171                 /* no op */
172                 dst[0] = src1[0];
173                 dst[1] = src1[1];
174                 dst[2] = src1[2];
175                 dst[3] = src1[3];
176         }
177 }
178
179 MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
180 {
181         if (src2[3] != 0) {
182                 /* straight darken operation */
183                 const int t = src2[3];
184                 const int mt = 255 - t;
185                 int tmp[3];
186
187                 tmp[0] = (mt * src1[0]) + (t * min_ii(src1[0], src2[0]));
188                 tmp[1] = (mt * src1[1]) + (t * min_ii(src1[1], src2[1]));
189                 tmp[2] = (mt * src1[2]) + (t * min_ii(src1[2], src2[2]));
190
191                 dst[0] = divide_round_i(tmp[0], 255);
192                 dst[1] = divide_round_i(tmp[1], 255);
193                 dst[2] = divide_round_i(tmp[2], 255);
194                 dst[3] = src1[3];
195         }
196         else {
197                 /* no op */
198                 dst[0] = src1[0];
199                 dst[1] = src1[1];
200                 dst[2] = src1[2];
201                 dst[3] = src1[3];
202         }
203 }
204
205 MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
206 {
207         if (src2[3] != 0) {
208                 /* straight so just modify alpha channel */
209                 const int t = src2[3];
210
211                 dst[0] = src1[0];
212                 dst[1] = src1[1];
213                 dst[2] = src1[2];
214                 dst[3] = max_ii(src1[3] - divide_round_i(t * src2[3], 255), 0);
215         }
216         else {
217                 /* no op */
218                 dst[0] = src1[0];
219                 dst[1] = src1[1];
220                 dst[2] = src1[2];
221                 dst[3] = src1[3];
222         }
223 }
224
225 MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
226 {
227         if (src2[3] != 0) {
228                 /* straight so just modify alpha channel */
229                 const int t = src2[3];
230
231                 dst[0] = src1[0];
232                 dst[1] = src1[1];
233                 dst[2] = src1[2];
234                 dst[3] = min_ii(src1[3] + divide_round_i(t * src2[3], 255), 255);
235         }
236         else {
237                 /* no op */
238                 dst[0] = src1[0];
239                 dst[1] = src1[1];
240                 dst[2] = src1[2];
241                 dst[3] = src1[3];
242         }
243 }
244
245 /* premultiplied alpha float blending modes */
246
247 MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
248 {
249         if (src2[3] != 0.0f) {
250                 /* premul over operation */
251                 const float t = src2[3];
252                 const float mt = 1.0f - t;
253
254                 dst[0] = mt * src1[0] + src2[0];
255                 dst[1] = mt * src1[1] + src2[1];
256                 dst[2] = mt * src1[2] + src2[2];
257                 dst[3] = mt * src1[3] + t;
258         }
259         else {
260                 /* no op */
261                 dst[0] = src1[0];
262                 dst[1] = src1[1];
263                 dst[2] = src1[2];
264                 dst[3] = src1[3];
265         }
266 }
267
268 MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
269 {
270         if (src2[3] != 0.0f) {
271                 /* unpremul > add > premul, simplified */
272                 dst[0] = src1[0] + src2[0] * src1[3];
273                 dst[1] = src1[1] + src2[1] * src1[3];
274                 dst[2] = src1[2] + src2[2] * src1[3];
275                 dst[3] = src1[3];
276         }
277         else {
278                 /* no op */
279                 dst[0] = src1[0];
280                 dst[1] = src1[1];
281                 dst[2] = src1[2];
282                 dst[3] = src1[3];
283         }
284 }
285
286 MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
287 {
288         if (src2[3] != 0.0f) {
289                 /* unpremul > subtract > premul, simplified */
290                 dst[0] = max_ff(src1[0] - src2[0] * src1[3], 0.0f);
291                 dst[1] = max_ff(src1[1] - src2[1] * src1[3], 0.0f);
292                 dst[2] = max_ff(src1[2] - src2[2] * src1[3], 0.0f);
293                 dst[3] = src1[3];
294         }
295         else {
296                 /* no op */
297                 dst[0] = src1[0];
298                 dst[1] = src1[1];
299                 dst[2] = src1[2];
300                 dst[3] = src1[3];
301         }
302 }
303
304 MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
305 {
306         if (src2[3] != 0.0f) {
307                 /* unpremul > multiply > premul, simplified */
308                 const float t = src2[3];
309                 const float mt = 1.0f - t;
310
311                 dst[0] = mt * src1[0] + src1[0] * src2[0] * src1[3];
312                 dst[1] = mt * src1[1] + src1[1] * src2[1] * src1[3];
313                 dst[2] = mt * src1[2] + src1[2] * src2[2] * src1[3];
314                 dst[3] = src1[3];
315         }
316         else {
317                 /* no op */
318                 dst[0] = src1[0];
319                 dst[1] = src1[1];
320                 dst[2] = src1[2];
321                 dst[3] = src1[3];
322         }
323 }
324
325 MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
326 {
327         if (src2[3] != 0.0f) {
328                 /* remap src2 to have same alpha as src1 premultiplied, take maximum of
329                  * src1 and src2, then blend it with src1 */
330                 const float t = src2[3];
331                 const float mt = 1.0f - t;
332                 const float map_alpha = src1[3]/src2[3];
333
334                 dst[0] = mt * src1[0] + t * max_ff(src1[0], src2[0] * map_alpha);
335                 dst[1] = mt * src1[1] + t * max_ff(src1[1], src2[1] * map_alpha);
336                 dst[2] = mt * src1[2] + t * max_ff(src1[2], src2[2] * map_alpha);
337                 dst[3] = src1[3];
338         }
339         else {
340                 /* no op */
341                 dst[0] = src1[0];
342                 dst[1] = src1[1];
343                 dst[2] = src1[2];
344                 dst[3] = src1[3];
345         }
346 }
347
348 MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
349 {
350         if (src2[3] != 0.0f) {
351                 /* remap src2 to have same alpha as src1 premultiplied, take minimum of
352                  * src1 and src2, then blend it with src1 */
353                 const float t = src2[3];
354                 const float mt = 1.0f - t;
355                 const float map_alpha = src1[3]/src2[3];
356
357                 dst[0] = mt * src1[0] + t * min_ff(src1[0], src2[0] * map_alpha);
358                 dst[1] = mt * src1[1] + t * min_ff(src1[1], src2[1] * map_alpha);
359                 dst[2] = mt * src1[2] + t * min_ff(src1[2], src2[2] * map_alpha);
360                 dst[3] = src1[3];
361         }
362         else {
363                 /* no op */
364                 dst[0] = src1[0];
365                 dst[1] = src1[1];
366                 dst[2] = src1[2];
367                 dst[3] = src1[3];
368         }
369 }
370
371 MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4])
372 {
373         if (src2[3] != 0.0f && src1[3] > 0.0f) {
374                 /* subtract alpha and remap RGB channels to match */
375                 const float alpha = max_ff(src1[3] - src2[3], 0.0f);
376                 const float map_alpha = alpha/src1[3];
377
378                 dst[0] *= map_alpha;
379                 dst[1] *= map_alpha;
380                 dst[2] *= map_alpha;
381                 dst[3] = alpha;
382         }
383         else {
384                 /* no op */
385                 dst[0] = src1[0];
386                 dst[1] = src1[1];
387                 dst[2] = src1[2];
388                 dst[3] = src1[3];
389         }
390 }
391
392 MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4])
393 {
394         if (src2[3] != 0.0f && src1[3] < 1.0f) {
395                 /* add alpha and remap RGB channels to match */
396                 const float alpha = min_ff(src1[3] + src2[3], 1.0f);
397                 const float map_alpha = (src1[3] > 0.0f) ? alpha/src1[3] : 1.0f;
398
399                 dst[0] *= map_alpha;
400                 dst[1] *= map_alpha;
401                 dst[2] *= map_alpha;
402                 dst[3] = alpha;
403         }
404         else {
405                 /* no op */
406                 dst[0] = src1[0];
407                 dst[1] = src1[1];
408                 dst[2] = src1[2];
409                 dst[3] = src1[3];
410         }
411 }
412
413 #endif /* __MATH_COLOR_BLEND_INLINE_C__ */