More painting fixes:
[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_blend_inline.c
27  *  \ingroup bli
28  */
29
30 #include "BLI_math_base.h"
31 #include "BLI_math_color.h"
32 #include "BLI_math_color_blend.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 MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft)
246 {
247         /* do color interpolation, but in premultiplied space so that RGB colors
248          * from zero alpha regions have no influence */
249         const int t = (int)(255 * ft);
250         const int mt = 255 - t;
251         int tmp = (mt * src1[3] + t * src2[3]);
252
253         if (tmp > 0) {
254                 dst[0] = divide_round_i(mt * src1[0] * src1[3] + t * src2[0] * src2[3], tmp);
255                 dst[1] = divide_round_i(mt * src1[1] * src1[3] + t * src2[1] * src2[3], tmp);
256                 dst[2] = divide_round_i(mt * src1[2] * src1[3] + t * src2[2] * src2[3], tmp);
257                 dst[3] = divide_round_i(tmp, 255);
258         }
259         else {
260                 dst[0] = src1[0];
261                 dst[1] = src1[1];
262                 dst[2] = src1[2];
263                 dst[3] = src1[3];
264         }
265 }
266
267 /* premultiplied alpha float blending modes */
268
269 MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
270 {
271         if (src2[3] != 0.0f) {
272                 /* premul over operation */
273                 const float t = src2[3];
274                 const float mt = 1.0f - t;
275
276                 dst[0] = mt * src1[0] + src2[0];
277                 dst[1] = mt * src1[1] + src2[1];
278                 dst[2] = mt * src1[2] + src2[2];
279                 dst[3] = mt * src1[3] + t;
280         }
281         else {
282                 /* no op */
283                 dst[0] = src1[0];
284                 dst[1] = src1[1];
285                 dst[2] = src1[2];
286                 dst[3] = src1[3];
287         }
288 }
289
290 MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
291 {
292         if (src2[3] != 0.0f) {
293                 /* unpremul > add > premul, simplified */
294                 dst[0] = src1[0] + src2[0] * src1[3];
295                 dst[1] = src1[1] + src2[1] * src1[3];
296                 dst[2] = src1[2] + src2[2] * src1[3];
297                 dst[3] = src1[3];
298         }
299         else {
300                 /* no op */
301                 dst[0] = src1[0];
302                 dst[1] = src1[1];
303                 dst[2] = src1[2];
304                 dst[3] = src1[3];
305         }
306 }
307
308 MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
309 {
310         if (src2[3] != 0.0f) {
311                 /* unpremul > subtract > premul, simplified */
312                 dst[0] = max_ff(src1[0] - src2[0] * src1[3], 0.0f);
313                 dst[1] = max_ff(src1[1] - src2[1] * src1[3], 0.0f);
314                 dst[2] = max_ff(src1[2] - src2[2] * src1[3], 0.0f);
315                 dst[3] = src1[3];
316         }
317         else {
318                 /* no op */
319                 dst[0] = src1[0];
320                 dst[1] = src1[1];
321                 dst[2] = src1[2];
322                 dst[3] = src1[3];
323         }
324 }
325
326 MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
327 {
328         if (src2[3] != 0.0f) {
329                 /* unpremul > multiply > premul, simplified */
330                 const float t = src2[3];
331                 const float mt = 1.0f - t;
332
333                 dst[0] = mt * src1[0] + src1[0] * src2[0] * src1[3];
334                 dst[1] = mt * src1[1] + src1[1] * src2[1] * src1[3];
335                 dst[2] = mt * src1[2] + src1[2] * src2[2] * src1[3];
336                 dst[3] = src1[3];
337         }
338         else {
339                 /* no op */
340                 dst[0] = src1[0];
341                 dst[1] = src1[1];
342                 dst[2] = src1[2];
343                 dst[3] = src1[3];
344         }
345 }
346
347 MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
348 {
349         if (src2[3] != 0.0f) {
350                 /* remap src2 to have same alpha as src1 premultiplied, take maximum of
351                  * src1 and src2, then blend it with src1 */
352                 const float t = src2[3];
353                 const float mt = 1.0f - t;
354                 const float map_alpha = src1[3] / src2[3];
355
356                 dst[0] = mt * src1[0] + t * max_ff(src1[0], src2[0] * map_alpha);
357                 dst[1] = mt * src1[1] + t * max_ff(src1[1], src2[1] * map_alpha);
358                 dst[2] = mt * src1[2] + t * max_ff(src1[2], src2[2] * map_alpha);
359                 dst[3] = src1[3];
360         }
361         else {
362                 /* no op */
363                 dst[0] = src1[0];
364                 dst[1] = src1[1];
365                 dst[2] = src1[2];
366                 dst[3] = src1[3];
367         }
368 }
369
370 MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
371 {
372         if (src2[3] != 0.0f) {
373                 /* remap src2 to have same alpha as src1 premultiplied, take minimum of
374                  * src1 and src2, then blend it with src1 */
375                 const float t = src2[3];
376                 const float mt = 1.0f - t;
377                 const float map_alpha = src1[3] / src2[3];
378
379                 dst[0] = mt * src1[0] + t * min_ff(src1[0], src2[0] * map_alpha);
380                 dst[1] = mt * src1[1] + t * min_ff(src1[1], src2[1] * map_alpha);
381                 dst[2] = mt * src1[2] + t * min_ff(src1[2], src2[2] * map_alpha);
382                 dst[3] = src1[3];
383         }
384         else {
385                 /* no op */
386                 dst[0] = src1[0];
387                 dst[1] = src1[1];
388                 dst[2] = src1[2];
389                 dst[3] = src1[3];
390         }
391 }
392
393 MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4])
394 {
395         if (src2[3] != 0.0f && src1[3] > 0.0f) {
396                 /* subtract alpha and remap RGB channels to match */
397                 float alpha = max_ff(src1[3] - src2[3], 0.0f);
398                 float map_alpha;
399
400                 if (alpha <= 0.0005f)
401                         alpha = 0.0f;
402
403                 map_alpha = alpha / src1[3];
404
405                 dst[0] = src1[0] * map_alpha;
406                 dst[1] = src1[1] * map_alpha;
407                 dst[2] = src1[2] * map_alpha;
408                 dst[3] = alpha;
409         }
410         else {
411                 /* no op */
412                 dst[0] = src1[0];
413                 dst[1] = src1[1];
414                 dst[2] = src1[2];
415                 dst[3] = src1[3];
416         }
417 }
418
419 MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4])
420 {
421         if (src2[3] != 0.0f && src1[3] < 1.0f) {
422                 /* add alpha and remap RGB channels to match */
423                 float alpha = min_ff(src1[3] + src2[3], 1.0f);
424                 float map_alpha;
425
426                 if (alpha >= 1.0f - 0.0005f)
427                         alpha = 1.0f;
428
429                 map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
430
431                 dst[0] = src1[0] * map_alpha;
432                 dst[1] = src1[1] * map_alpha;
433                 dst[2] = src1[2] * map_alpha;
434                 dst[3] = alpha;
435         }
436         else {
437                 /* no op */
438                 dst[0] = src1[0];
439                 dst[1] = src1[1];
440                 dst[2] = src1[2];
441                 dst[3] = src1[3];
442         }
443 }
444
445 MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
446 {
447         /* interpolation, colors are premultiplied so it goes fine */
448         float mt = 1.0f - t;
449
450         dst[0] = mt * src1[0] + t * src2[0];
451         dst[1] = mt * src1[1] + t * src2[1];
452         dst[2] = mt * src1[2] + t * src2[2];
453         dst[3] = mt * src1[3] + t * src2[3];
454 }
455
456 #endif /* __MATH_COLOR_BLEND_INLINE_C__ */