Blender V4.5
rectop.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 <algorithm>
10#include <cstdlib>
11
12#include "BLI_math_base.h"
13#include "BLI_math_color.h"
15#include "BLI_math_vector.h"
16#include "BLI_rect.h"
17#include "BLI_task.hh"
18#include "BLI_utildefines.h"
19
20#include "IMB_imbuf.hh"
21#include "IMB_imbuf_types.hh"
22
24
25#include "MEM_guardedalloc.h"
26
27#include <cstring>
28
30 const uchar src1[4],
31 const uchar src2[4],
32 IMB_BlendMode mode)
33{
34 switch (mode) {
35 case IMB_BLEND_MIX:
36 blend_color_mix_byte(dst, src1, src2);
37 break;
38 case IMB_BLEND_ADD:
39 blend_color_add_byte(dst, src1, src2);
40 break;
41 case IMB_BLEND_SUB:
42 blend_color_sub_byte(dst, src1, src2);
43 break;
44 case IMB_BLEND_MUL:
45 blend_color_mul_byte(dst, src1, src2);
46 break;
48 blend_color_lighten_byte(dst, src1, src2);
49 break;
51 blend_color_darken_byte(dst, src1, src2);
52 break;
54 blend_color_erase_alpha_byte(dst, src1, src2);
55 break;
57 blend_color_add_alpha_byte(dst, src1, src2);
58 break;
60 blend_color_overlay_byte(dst, src1, src2);
61 break;
63 blend_color_hardlight_byte(dst, src1, src2);
64 break;
66 blend_color_burn_byte(dst, src1, src2);
67 break;
69 blend_color_linearburn_byte(dst, src1, src2);
70 break;
72 blend_color_dodge_byte(dst, src1, src2);
73 break;
75 blend_color_screen_byte(dst, src1, src2);
76 break;
78 blend_color_softlight_byte(dst, src1, src2);
79 break;
81 blend_color_pinlight_byte(dst, src1, src2);
82 break;
84 blend_color_linearlight_byte(dst, src1, src2);
85 break;
87 blend_color_vividlight_byte(dst, src1, src2);
88 break;
90 blend_color_difference_byte(dst, src1, src2);
91 break;
93 blend_color_exclusion_byte(dst, src1, src2);
94 break;
95 case IMB_BLEND_COLOR:
96 blend_color_color_byte(dst, src1, src2);
97 break;
98 case IMB_BLEND_HUE:
99 blend_color_hue_byte(dst, src1, src2);
100 break;
102 blend_color_saturation_byte(dst, src1, src2);
103 break;
105 blend_color_luminosity_byte(dst, src1, src2);
106 break;
107
108 default:
109 dst[0] = src1[0];
110 dst[1] = src1[1];
111 dst[2] = src1[2];
112 dst[3] = src1[3];
113 break;
114 }
115}
116
117void IMB_blend_color_float(float dst[4],
118 const float src1[4],
119 const float src2[4],
120 IMB_BlendMode mode)
121{
122 switch (mode) {
123 case IMB_BLEND_MIX:
124 blend_color_mix_float(dst, src1, src2);
125 break;
126 case IMB_BLEND_ADD:
127 blend_color_add_float(dst, src1, src2);
128 break;
129 case IMB_BLEND_SUB:
130 blend_color_sub_float(dst, src1, src2);
131 break;
132 case IMB_BLEND_MUL:
133 blend_color_mul_float(dst, src1, src2);
134 break;
136 blend_color_lighten_float(dst, src1, src2);
137 break;
138 case IMB_BLEND_DARKEN:
139 blend_color_darken_float(dst, src1, src2);
140 break;
142 blend_color_erase_alpha_float(dst, src1, src2);
143 break;
145 blend_color_add_alpha_float(dst, src1, src2);
146 break;
148 blend_color_overlay_float(dst, src1, src2);
149 break;
151 blend_color_hardlight_float(dst, src1, src2);
152 break;
154 blend_color_burn_float(dst, src1, src2);
155 break;
157 blend_color_linearburn_float(dst, src1, src2);
158 break;
160 blend_color_dodge_float(dst, src1, src2);
161 break;
162 case IMB_BLEND_SCREEN:
163 blend_color_screen_float(dst, src1, src2);
164 break;
166 blend_color_softlight_float(dst, src1, src2);
167 break;
169 blend_color_pinlight_float(dst, src1, src2);
170 break;
172 blend_color_linearlight_float(dst, src1, src2);
173 break;
175 blend_color_vividlight_float(dst, src1, src2);
176 break;
178 blend_color_difference_float(dst, src1, src2);
179 break;
181 blend_color_exclusion_float(dst, src1, src2);
182 break;
183 case IMB_BLEND_COLOR:
184 blend_color_color_float(dst, src1, src2);
185 break;
186 case IMB_BLEND_HUE:
187 blend_color_hue_float(dst, src1, src2);
188 break;
190 blend_color_saturation_float(dst, src1, src2);
191 break;
193 blend_color_luminosity_float(dst, src1, src2);
194 break;
195 default:
196 dst[0] = src1[0];
197 dst[1] = src1[1];
198 dst[2] = src1[2];
199 dst[3] = src1[3];
200 break;
201 }
202}
203
204/* -------------------------------------------------------------------- */
207
208static void rect_crop_4bytes(void **buf_p, const int size_src[2], const rcti *crop)
209{
210 if (*buf_p == nullptr) {
211 return;
212 }
213 const int size_dst[2] = {
214 BLI_rcti_size_x(crop) + 1,
215 BLI_rcti_size_y(crop) + 1,
216 };
217 uint *src = static_cast<uint *>(*buf_p);
218 uint *dst = src + crop->ymin * size_src[0] + crop->xmin;
219 for (int y = 0; y < size_dst[1]; y++, src += size_dst[0], dst += size_src[0]) {
220 memmove(src, dst, sizeof(uint) * size_dst[0]);
221 }
222 *buf_p = MEM_reallocN(*buf_p, sizeof(uint) * size_dst[0] * size_dst[1]);
223}
224
225static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *crop)
226{
227 if (*buf_p == nullptr) {
228 return;
229 }
230 const int size_dst[2] = {
231 BLI_rcti_size_x(crop) + 1,
232 BLI_rcti_size_y(crop) + 1,
233 };
234 uint(*src)[4] = static_cast<uint(*)[4]>(*buf_p);
235 uint(*dst)[4] = src + crop->ymin * size_src[0] + crop->xmin;
236 for (int y = 0; y < size_dst[1]; y++, src += size_dst[0], dst += size_src[0]) {
237 memmove(src, dst, sizeof(uint[4]) * size_dst[0]);
238 }
239 *buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]);
240}
241
242void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
243{
244 const int size_src[2] = {
245 ibuf->x,
246 ibuf->y,
247 };
248 const int size_dst[2] = {
249 BLI_rcti_size_x(crop) + 1,
250 BLI_rcti_size_y(crop) + 1,
251 };
252 BLI_assert(size_dst[0] > 0 && size_dst[1] > 0);
253 BLI_assert(crop->xmin >= 0 && crop->ymin >= 0);
254 BLI_assert(crop->xmax < ibuf->x && crop->ymax < ibuf->y);
255
256 if ((size_dst[0] == ibuf->x) && (size_dst[1] == ibuf->y)) {
257 return;
258 }
259
260 /* TODO(sergey: Validate ownership. */
261 rect_crop_4bytes((void **)&ibuf->byte_buffer.data, size_src, crop);
262 rect_crop_16bytes((void **)&ibuf->float_buffer.data, size_src, crop);
263
264 ibuf->x = size_dst[0];
265 ibuf->y = size_dst[1];
266}
267
271static void rect_realloc_4bytes(void **buf_p, const uint size[2])
272{
273 if (*buf_p == nullptr) {
274 return;
275 }
276 MEM_freeN(*buf_p);
277 *buf_p = MEM_malloc_arrayN<uint>(size_t(size[0]) * size_t(size[1]), __func__);
278}
279
280static void rect_realloc_16bytes(void **buf_p, const uint size[2])
281{
282 if (*buf_p == nullptr) {
283 return;
284 }
285 MEM_freeN(*buf_p);
286 *buf_p = MEM_malloc_arrayN<uint>(4 * size_t(size[0]) * size_t(size[1]), __func__);
287}
288
289void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
290{
291 BLI_assert(size[0] > 0 && size[1] > 0);
292 if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) {
293 return;
294 }
295
296 /* TODO(sergey: Validate ownership. */
297 rect_realloc_4bytes((void **)&ibuf->byte_buffer.data, size);
298 rect_realloc_16bytes((void **)&ibuf->float_buffer.data, size);
299
300 ibuf->x = size[0];
301 ibuf->y = size[1];
302}
303
305
306/* clipping */
307
309 const ImBuf *sbuf,
310 int *destx,
311 int *desty,
312 int *srcx,
313 int *srcy,
314 int *width,
315 int *height)
316{
317 int tmp;
318
319 if (dbuf == nullptr) {
320 return;
321 }
322
323 if (*destx < 0) {
324 *srcx -= *destx;
325 *width += *destx;
326 *destx = 0;
327 }
328 if (*srcx < 0) {
329 *destx -= *srcx;
330 *width += *srcx;
331 *srcx = 0;
332 }
333 if (*desty < 0) {
334 *srcy -= *desty;
335 *height += *desty;
336 *desty = 0;
337 }
338 if (*srcy < 0) {
339 *desty -= *srcy;
340 *height += *srcy;
341 *srcy = 0;
342 }
343
344 tmp = dbuf->x - *destx;
345 *width = std::min(*width, tmp);
346 tmp = dbuf->y - *desty;
347 *height = std::min(*height, tmp);
348
349 if (sbuf) {
350 tmp = sbuf->x - *srcx;
351 *width = std::min(*width, tmp);
352 tmp = sbuf->y - *srcy;
353 *height = std::min(*height, tmp);
354 }
355
356 if ((*height <= 0) || (*width <= 0)) {
357 *width = 0;
358 *height = 0;
359 }
360}
361
362static void imb_rectclip3(ImBuf *dbuf,
363 const ImBuf *obuf,
364 const ImBuf *sbuf,
365 int *destx,
366 int *desty,
367 int *origx,
368 int *origy,
369 int *srcx,
370 int *srcy,
371 int *width,
372 int *height)
373{
374 int tmp;
375
376 if (dbuf == nullptr) {
377 return;
378 }
379
380 if (*destx < 0) {
381 *srcx -= *destx;
382 *origx -= *destx;
383 *width += *destx;
384 *destx = 0;
385 }
386 if (*origx < 0) {
387 *destx -= *origx;
388 *srcx -= *origx;
389 *width += *origx;
390 *origx = 0;
391 }
392 if (*srcx < 0) {
393 *destx -= *srcx;
394 *origx -= *srcx;
395 *width += *srcx;
396 *srcx = 0;
397 }
398
399 if (*desty < 0) {
400 *srcy -= *desty;
401 *origy -= *desty;
402 *height += *desty;
403 *desty = 0;
404 }
405 if (*origy < 0) {
406 *desty -= *origy;
407 *srcy -= *origy;
408 *height += *origy;
409 *origy = 0;
410 }
411 if (*srcy < 0) {
412 *desty -= *srcy;
413 *origy -= *srcy;
414 *height += *srcy;
415 *srcy = 0;
416 }
417
418 tmp = dbuf->x - *destx;
419 *width = std::min(*width, tmp);
420 tmp = dbuf->y - *desty;
421 *height = std::min(*height, tmp);
422
423 if (obuf) {
424 tmp = obuf->x - *origx;
425 *width = std::min(*width, tmp);
426 tmp = obuf->y - *origy;
427 *height = std::min(*height, tmp);
428 }
429
430 if (sbuf) {
431 tmp = sbuf->x - *srcx;
432 *width = std::min(*width, tmp);
433 tmp = sbuf->y - *srcy;
434 *height = std::min(*height, tmp);
435 }
436
437 if ((*height <= 0) || (*width <= 0)) {
438 *width = 0;
439 *height = 0;
440 }
441}
442
443/* copy and blend */
444
446 const ImBuf *sbuf,
447 int destx,
448 int desty,
449 int srcx,
450 int srcy,
451 int width,
452 int height)
453{
454 IMB_rectblend(dbuf,
455 dbuf,
456 sbuf,
457 nullptr,
458 nullptr,
459 nullptr,
460 0,
461 destx,
462 desty,
463 destx,
464 desty,
465 srcx,
466 srcy,
467 width,
468 height,
470 false);
471}
472
473using IMB_blend_func = void (*)(uchar *dst, const uchar *src1, const uchar *src2);
474using IMB_blend_func_float = void (*)(float *dst, const float *src1, const float *src2);
475
477 const ImBuf *obuf,
478 const ImBuf *sbuf,
479 ushort *dmask,
480 const ushort *curvemask,
481 const ushort *texmask,
482 float mask_max,
483 int destx,
484 int desty,
485 int origx,
486 int origy,
487 int srcx,
488 int srcy,
489 int width,
490 int height,
491 IMB_BlendMode mode,
492 bool accumulate)
493{
494 uint *drect = nullptr, *orect = nullptr, *srect = nullptr, *dr, *outr, *sr;
495 float *drectf = nullptr, *orectf = nullptr, *srectf = nullptr, *drf, *orf, *srf;
496 const ushort *cmaskrect = curvemask, *cmr;
497 ushort *dmaskrect = dmask, *dmr;
498 const ushort *texmaskrect = texmask, *tmr;
499 int srcskip, destskip, origskip, x;
500 IMB_blend_func func = nullptr;
501 IMB_blend_func_float func_float = nullptr;
502
503 if (dbuf == nullptr || obuf == nullptr) {
504 return;
505 }
506
507 imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &srcx, &srcy, &width, &height);
508
509 if (width == 0 || height == 0) {
510 return;
511 }
512 if (sbuf && sbuf->channels != 4) {
513 return;
514 }
515 if (dbuf->channels != 4) {
516 return;
517 }
518
519 const bool do_char = (sbuf && sbuf->byte_buffer.data && dbuf->byte_buffer.data &&
520 obuf->byte_buffer.data);
521 const bool do_float = (sbuf && sbuf->float_buffer.data && dbuf->float_buffer.data &&
522 obuf->float_buffer.data);
523
524 if (do_char) {
525 drect = (uint *)dbuf->byte_buffer.data + size_t(desty) * dbuf->x + destx;
526 orect = (uint *)obuf->byte_buffer.data + size_t(origy) * obuf->x + origx;
527 }
528 if (do_float) {
529 drectf = dbuf->float_buffer.data + (size_t(desty) * dbuf->x + destx) * 4;
530 orectf = obuf->float_buffer.data + (size_t(origy) * obuf->x + origx) * 4;
531 }
532
533 if (dmaskrect) {
534 dmaskrect += size_t(origy) * obuf->x + origx;
535 }
536
537 destskip = dbuf->x;
538 origskip = obuf->x;
539
540 if (sbuf) {
541 if (do_char) {
542 srect = (uint *)sbuf->byte_buffer.data + size_t(srcy) * sbuf->x + srcx;
543 }
544 if (do_float) {
545 srectf = sbuf->float_buffer.data + (size_t(srcy) * sbuf->x + srcx) * 4;
546 }
547 srcskip = sbuf->x;
548
549 if (cmaskrect) {
550 cmaskrect += size_t(srcy) * sbuf->x + srcx;
551 }
552
553 if (texmaskrect) {
554 texmaskrect += size_t(srcy) * sbuf->x + srcx;
555 }
556 }
557 else {
558 srect = drect;
559 srectf = drectf;
560 srcskip = destskip;
561 }
562
563 if (mode == IMB_BLEND_COPY) {
564 /* copy */
565 for (; height > 0; height--) {
566 if (do_char) {
567 memcpy(drect, srect, width * sizeof(int));
568 drect += destskip;
569 srect += srcskip;
570 }
571
572 if (do_float) {
573 memcpy(drectf, srectf, sizeof(float[4]) * width);
574 drectf += destskip * 4;
575 srectf += srcskip * 4;
576 }
577 }
578 }
579 else if (mode == IMB_BLEND_COPY_RGB) {
580 /* copy rgb only */
581 for (; height > 0; height--) {
582 if (do_char) {
583 dr = drect;
584 sr = srect;
585 for (x = width; x > 0; x--, dr++, sr++) {
586 ((char *)dr)[0] = ((char *)sr)[0];
587 ((char *)dr)[1] = ((char *)sr)[1];
588 ((char *)dr)[2] = ((char *)sr)[2];
589 }
590 drect += destskip;
591 srect += srcskip;
592 }
593
594 if (do_float) {
595 drf = drectf;
596 srf = srectf;
597 for (x = width; x > 0; x--, drf += 4, srf += 4) {
598 float map_alpha = (srf[3] == 0.0f) ? drf[3] : drf[3] / srf[3];
599
600 drf[0] = srf[0] * map_alpha;
601 drf[1] = srf[1] * map_alpha;
602 drf[2] = srf[2] * map_alpha;
603 }
604 drectf += destskip * 4;
605 srectf += srcskip * 4;
606 }
607 }
608 }
609 else if (mode == IMB_BLEND_COPY_ALPHA) {
610 /* copy alpha only */
611 for (; height > 0; height--) {
612 if (do_char) {
613 dr = drect;
614 sr = srect;
615 for (x = width; x > 0; x--, dr++, sr++) {
616 ((char *)dr)[3] = ((char *)sr)[3];
617 }
618 drect += destskip;
619 srect += srcskip;
620 }
621
622 if (do_float) {
623 drf = drectf;
624 srf = srectf;
625 for (x = width; x > 0; x--, drf += 4, srf += 4) {
626 drf[3] = srf[3];
627 }
628 drectf += destskip * 4;
629 srectf += srcskip * 4;
630 }
631 }
632 }
633 else {
634 switch (mode) {
635 case IMB_BLEND_MIX:
638 func_float = blend_color_mix_float;
639 break;
640 case IMB_BLEND_ADD:
642 func_float = blend_color_add_float;
643 break;
644 case IMB_BLEND_SUB:
646 func_float = blend_color_sub_float;
647 break;
648 case IMB_BLEND_MUL:
650 func_float = blend_color_mul_float;
651 break;
654 func_float = blend_color_lighten_float;
655 break;
656 case IMB_BLEND_DARKEN:
658 func_float = blend_color_darken_float;
659 break;
663 break;
666 func_float = blend_color_add_alpha_float;
667 break;
670 func_float = blend_color_overlay_float;
671 break;
674 func_float = blend_color_hardlight_float;
675 break;
678 func_float = blend_color_burn_float;
679 break;
682 func_float = blend_color_linearburn_float;
683 break;
686 func_float = blend_color_dodge_float;
687 break;
688 case IMB_BLEND_SCREEN:
690 func_float = blend_color_screen_float;
691 break;
694 func_float = blend_color_softlight_float;
695 break;
698 func_float = blend_color_pinlight_float;
699 break;
703 break;
706 func_float = blend_color_vividlight_float;
707 break;
710 func_float = blend_color_difference_float;
711 break;
714 func_float = blend_color_exclusion_float;
715 break;
716 case IMB_BLEND_COLOR:
718 func_float = blend_color_color_float;
719 break;
720 case IMB_BLEND_HUE:
722 func_float = blend_color_hue_float;
723 break;
726 func_float = blend_color_saturation_float;
727 break;
730 func_float = blend_color_luminosity_float;
731 break;
732 default:
733 break;
734 }
735
736 /* blend */
737 for (; height > 0; height--) {
738 if (do_char) {
739 dr = drect;
740 outr = orect;
741 sr = srect;
742
743 if (cmaskrect) {
744 /* mask accumulation for painting */
745 cmr = cmaskrect;
746 tmr = texmaskrect;
747
748 /* destination mask present, do max alpha masking */
749 if (dmaskrect) {
750 dmr = dmaskrect;
751 for (x = width; x > 0; x--, dr++, outr++, sr++, dmr++, cmr++) {
752 uchar *src = (uchar *)sr;
753 float mask_lim = mask_max * (*cmr);
754
755 if (texmaskrect) {
756 mask_lim *= ((*tmr++) / 65535.0f);
757 }
758
759 if (src[3] && mask_lim) {
760 float mask;
761
762 if (accumulate) {
763 mask = *dmr + mask_lim;
764 }
765 else {
766 mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f));
767 }
768
769 mask = min_ff(mask, 65535.0);
770
771 if (mask > *dmr) {
772 uchar mask_src[4];
773
774 *dmr = mask;
775
776 mask_src[0] = src[0];
777 mask_src[1] = src[1];
778 mask_src[2] = src[2];
779
780 if (mode == IMB_BLEND_INTERPOLATE) {
781 mask_src[3] = src[3];
783 (uchar *)dr, (uchar *)outr, mask_src, mask / 65535.0f);
784 }
785 else {
786 mask_src[3] = divide_round_i(src[3] * mask, 65535);
787 func((uchar *)dr, (uchar *)outr, mask_src);
788 }
789 }
790 }
791 }
792 dmaskrect += origskip;
793 }
794 /* No destination mask buffer, do regular blend with mask-texture if present. */
795 else {
796 for (x = width; x > 0; x--, dr++, outr++, sr++, cmr++) {
797 uchar *src = (uchar *)sr;
798 float mask = mask_max * float(*cmr);
799
800 if (texmaskrect) {
801 mask *= (float(*tmr++) / 65535.0f);
802 }
803
804 mask = min_ff(mask, 65535.0);
805
806 if (src[3] && (mask > 0.0f)) {
807 uchar mask_src[4];
808
809 mask_src[0] = src[0];
810 mask_src[1] = src[1];
811 mask_src[2] = src[2];
812
813 if (mode == IMB_BLEND_INTERPOLATE) {
814 mask_src[3] = src[3];
816 (uchar *)dr, (uchar *)outr, mask_src, mask / 65535.0f);
817 }
818 else {
819 mask_src[3] = divide_round_i(src[3] * mask, 65535);
820 func((uchar *)dr, (uchar *)outr, mask_src);
821 }
822 }
823 }
824 }
825
826 cmaskrect += srcskip;
827 if (texmaskrect) {
828 texmaskrect += srcskip;
829 }
830 }
831 else {
832 /* regular blending */
833 for (x = width; x > 0; x--, dr++, outr++, sr++) {
834 if (((uchar *)sr)[3]) {
835 func((uchar *)dr, (uchar *)outr, (uchar *)sr);
836 }
837 }
838 }
839
840 drect += destskip;
841 orect += origskip;
842 srect += srcskip;
843 }
844
845 if (do_float) {
846 drf = drectf;
847 orf = orectf;
848 srf = srectf;
849
850 if (cmaskrect) {
851 /* mask accumulation for painting */
852 cmr = cmaskrect;
853 tmr = texmaskrect;
854
855 /* destination mask present, do max alpha masking */
856 if (dmaskrect) {
857 dmr = dmaskrect;
858 for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, cmr++) {
859 float mask_lim = mask_max * (*cmr);
860
861 if (texmaskrect) {
862 mask_lim *= ((*tmr++) / 65535.0f);
863 }
864
865 if (srf[3] && mask_lim) {
866 float mask;
867
868 if (accumulate) {
869 mask = min_ff(*dmr + mask_lim, 65535.0);
870 }
871 else {
872 mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f));
873 }
874
875 mask = min_ff(mask, 65535.0);
876
877 if (mask > *dmr) {
878 *dmr = mask;
879
880 if (mode == IMB_BLEND_INTERPOLATE) {
881 blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f);
882 }
883 else {
884 float mask_srf[4];
885 mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
886 func_float(drf, orf, mask_srf);
887 }
888 }
889 }
890 }
891 dmaskrect += origskip;
892 }
893 /* No destination mask buffer, do regular blend with mask-texture if present. */
894 else {
895 for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, cmr++) {
896 float mask = mask_max * float(*cmr);
897
898 if (texmaskrect) {
899 mask *= (float(*tmr++) / 65535.0f);
900 }
901
902 mask = min_ff(mask, 65535.0);
903
904 if (srf[3] && (mask > 0.0f)) {
905 if (mode == IMB_BLEND_INTERPOLATE) {
906 blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f);
907 }
908 else {
909 float mask_srf[4];
910 mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
911 func_float(drf, orf, mask_srf);
912 }
913 }
914 }
915 }
916
917 cmaskrect += srcskip;
918 if (texmaskrect) {
919 texmaskrect += srcskip;
920 }
921 }
922 else {
923 /* regular blending */
924 for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) {
925 if (srf[3] != 0) {
926 func_float(drf, orf, srf);
927 }
928 }
929 }
930
931 drectf += destskip * 4;
932 orectf += origskip * 4;
933 srectf += srcskip * 4;
934 }
935 }
936 }
937}
938
940 const ImBuf *obuf,
941 const ImBuf *sbuf,
942 ushort *dmask,
943 const ushort *curvemask,
944 const ushort *texmask,
945 float mask_max,
946 int destx,
947 int desty,
948 int origx,
949 int origy,
950 int srcx,
951 int srcy,
952 int width,
953 int height,
954 IMB_BlendMode mode,
955 bool accumulate)
956{
957 using namespace blender;
958 threading::parallel_for(IndexRange(height), 16, [&](const IndexRange y_range) {
959 IMB_rectblend(dbuf,
960 obuf,
961 sbuf,
962 dmask,
963 curvemask,
964 texmask,
965 mask_max,
966 destx,
967 desty + y_range.first(),
968 origx,
969 origy + y_range.first(),
970 srcx,
971 srcy + y_range.first(),
972 width,
973 y_range.size(),
974 mode,
975 accumulate);
976 });
977}
978
979void IMB_rectfill(ImBuf *drect, const float col[4])
980{
981 size_t num;
982
983 if (drect->byte_buffer.data) {
984 uint *rrect = (uint *)drect->byte_buffer.data;
985 char ccol[4];
986
987 ccol[0] = int(col[0] * 255);
988 ccol[1] = int(col[1] * 255);
989 ccol[2] = int(col[2] * 255);
990 ccol[3] = int(col[3] * 255);
991
992 num = IMB_get_pixel_count(drect);
993 for (; num > 0; num--) {
994 *rrect++ = *((uint *)ccol);
995 }
996 }
997
998 if (drect->float_buffer.data) {
999 float *rrectf = drect->float_buffer.data;
1000
1001 num = IMB_get_pixel_count(drect);
1002 for (; num > 0; num--) {
1003 *rrectf++ = col[0];
1004 *rrectf++ = col[1];
1005 *rrectf++ = col[2];
1006 *rrectf++ = col[3];
1007 }
1008 }
1009}
1010
1012 const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
1013{
1014 /* Sanity checks. */
1015 BLI_assert(ibuf->channels == 4);
1016
1017 if (ibuf->channels != 4) {
1018 return;
1019 }
1020
1021 int width = ibuf->x;
1022 int height = ibuf->y;
1023 CLAMP(x1, 0, width);
1024 CLAMP(x2, 0, width);
1025 CLAMP(y1, 0, height);
1026 CLAMP(y2, 0, height);
1027
1028 if (x1 > x2) {
1029 std::swap(x1, x2);
1030 }
1031 if (y1 > y2) {
1032 std::swap(y1, y2);
1033 }
1034 if (x1 == x2 || y1 == y2) {
1035 return;
1036 }
1037
1038 const uchar col_char[4] = {
1039 uchar(col[0] * 255), uchar(col[1] * 255), uchar(col[2] * 255), uchar(col[3] * 255)};
1040
1041 for (int y = y1; y < y2; y++) {
1042 for (int x = x1; x < x2; x++) {
1043 size_t offset = size_t(ibuf->x) * y * 4 + 4 * x;
1044
1045 if (ibuf->byte_buffer.data) {
1046 uchar *rrect = ibuf->byte_buffer.data + offset;
1047 memcpy(rrect, col_char, sizeof(uchar[4]));
1048 }
1049
1050 if (ibuf->float_buffer.data) {
1051 float *rrectf = ibuf->float_buffer.data + offset;
1052 memcpy(rrectf, col, sizeof(float[4]));
1053 }
1054 }
1055 }
1056}
1057
1059 float *rectf,
1060 int width,
1061 int height,
1062 const float col[4],
1063 const ColorManagedDisplay *display,
1064 int x1,
1065 int y1,
1066 int x2,
1067 int y2)
1068{
1069 if ((!rect && !rectf) || (!col) || col[3] == 0.0f) {
1070 return;
1071 }
1072
1073 /* sanity checks for coords */
1074 CLAMP(x1, 0, width);
1075 CLAMP(x2, 0, width);
1076 CLAMP(y1, 0, height);
1077 CLAMP(y2, 0, height);
1078
1079 if (x1 > x2) {
1080 std::swap(x1, x2);
1081 }
1082 if (y1 > y2) {
1083 std::swap(y1, y2);
1084 }
1085 if (x1 == x2 || y1 == y2) {
1086 return;
1087 }
1088 const int x_span = x2 - x1;
1089 const int y_span = y2 - y1;
1090
1091 /* Alpha. */
1092 const float a = col[3];
1093 /* Alpha inverted. */
1094 const float ai = 1 - a;
1095 /* Alpha, inverted, ai/255.0 - Convert char to float at the same time. */
1096 const float aich = ai / 255.0f;
1097
1098 if (rect) {
1099 uchar *pixel;
1100 uchar chr = 0, chg = 0, chb = 0;
1101 float fr = 0, fg = 0, fb = 0;
1102
1103 const int alphaint = unit_float_to_uchar_clamp(a);
1104
1105 if (a == 1.0f) {
1109 }
1110 else {
1111 fr = col[0] * a;
1112 fg = col[1] * a;
1113 fb = col[2] * a;
1114 }
1115 for (int j = 0; j < y_span; j++) {
1116 pixel = rect + (4 * (((size_t(y1) + size_t(j)) * size_t(width)) + size_t(x1)));
1117 for (int i = 0; i < x_span; i++) {
1118 BLI_assert(pixel >= rect && pixel < rect + (4 * (size_t(width) * size_t(height))));
1119 if (a == 1.0f) {
1120 pixel[0] = chr;
1121 pixel[1] = chg;
1122 pixel[2] = chb;
1123 pixel[3] = 255;
1124 }
1125 else {
1126 int alphatest;
1127 pixel[0] = char((fr + (float(pixel[0]) * aich)) * 255.0f);
1128 pixel[1] = char((fg + (float(pixel[1]) * aich)) * 255.0f);
1129 pixel[2] = char((fb + (float(pixel[2]) * aich)) * 255.0f);
1130 pixel[3] = char((alphatest = (int(pixel[3]) + alphaint)) < 255 ? alphatest : 255);
1131 }
1132 pixel += 4;
1133 }
1134 }
1135 }
1136
1137 if (rectf) {
1138 float col_conv[4];
1139 float *pixel;
1140
1141 if (display) {
1142 copy_v4_v4(col_conv, col);
1144 }
1145 else {
1146 srgb_to_linearrgb_v4(col_conv, col);
1147 }
1148
1149 for (int j = 0; j < y_span; j++) {
1150 pixel = rectf + (4 * (((size_t(y1) + j) * size_t(width)) + size_t(x1)));
1151 for (int i = 0; i < x_span; i++) {
1152 BLI_assert(pixel >= rectf && pixel < rectf + (4 * (size_t(width) * size_t(height))));
1153 if (a == 1.0f) {
1154 pixel[0] = col_conv[0];
1155 pixel[1] = col_conv[1];
1156 pixel[2] = col_conv[2];
1157 pixel[3] = 1.0f;
1158 }
1159 else {
1160 float alphatest;
1161 pixel[0] = (col_conv[0] * a) + (pixel[0] * ai);
1162 pixel[1] = (col_conv[1] * a) + (pixel[1] * ai);
1163 pixel[2] = (col_conv[2] * a) + (pixel[2] * ai);
1164 pixel[3] = (alphatest = (pixel[3] + a)) < 1.0f ? alphatest : 1.0f;
1165 }
1166 pixel += 4;
1167 }
1168 }
1169 }
1170}
1171
1173 const float col[4],
1174 int x1,
1175 int y1,
1176 int x2,
1177 int y2,
1178 const ColorManagedDisplay *display)
1179{
1180 if (!ibuf) {
1181 return;
1182 }
1184 ibuf->float_buffer.data,
1185 ibuf->x,
1186 ibuf->y,
1187 col,
1188 display,
1189 x1,
1190 y1,
1191 x2,
1192 y2);
1193}
1194
1195void IMB_rectfill_alpha(ImBuf *ibuf, const float value)
1196{
1197 size_t i;
1198
1199 if (ibuf->float_buffer.data && (ibuf->channels == 4)) {
1200 float *fbuf = ibuf->float_buffer.data + 3;
1201 for (i = IMB_get_pixel_count(ibuf); i > 0; i--, fbuf += 4) {
1202 *fbuf = value;
1203 }
1204 }
1205
1206 if (ibuf->byte_buffer.data) {
1207 const uchar cvalue = value * 255;
1208 uchar *cbuf = ibuf->byte_buffer.data + 3;
1209 for (i = IMB_get_pixel_count(ibuf); i > 0; i--, cbuf += 4) {
1210 *cbuf = cvalue;
1211 }
1212 }
1213}
blender::ocio::Display ColorManagedDisplay
Definition BLF_api.hh:35
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float min_ff(float a, float b)
MINLINE int divide_round_i(int a, int b)
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_linearburn_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_saturation_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_luminosity_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_pinlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_screen_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_vividlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_difference_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_burn_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_color_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_overlay_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_dodge_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_hardlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_softlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_hue_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_exclusion_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft)
MINLINE void blend_color_linearlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
ATTR_WARN_UNUSED_RESULT const size_t num
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
unsigned char uchar
unsigned int uint
unsigned short ushort
#define CLAMP(a, b, c)
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], const ColorManagedDisplay *display)
IMB_BlendMode
Definition IMB_imbuf.hh:185
@ IMB_BLEND_EXCLUSION
Definition IMB_imbuf.hh:205
@ IMB_BLEND_DIFFERENCE
Definition IMB_imbuf.hh:204
@ IMB_BLEND_HARDLIGHT
Definition IMB_imbuf.hh:195
@ IMB_BLEND_COLORBURN
Definition IMB_imbuf.hh:196
@ IMB_BLEND_COLORDODGE
Definition IMB_imbuf.hh:198
@ IMB_BLEND_ERASE_ALPHA
Definition IMB_imbuf.hh:192
@ IMB_BLEND_SCREEN
Definition IMB_imbuf.hh:199
@ IMB_BLEND_HUE
Definition IMB_imbuf.hh:206
@ IMB_BLEND_MUL
Definition IMB_imbuf.hh:189
@ IMB_BLEND_ADD_ALPHA
Definition IMB_imbuf.hh:193
@ IMB_BLEND_DARKEN
Definition IMB_imbuf.hh:191
@ IMB_BLEND_OVERLAY
Definition IMB_imbuf.hh:194
@ IMB_BLEND_SATURATION
Definition IMB_imbuf.hh:207
@ IMB_BLEND_VIVIDLIGHT
Definition IMB_imbuf.hh:202
@ IMB_BLEND_LUMINOSITY
Definition IMB_imbuf.hh:208
@ IMB_BLEND_LIGHTEN
Definition IMB_imbuf.hh:190
@ IMB_BLEND_SOFTLIGHT
Definition IMB_imbuf.hh:200
@ IMB_BLEND_COPY_RGB
Definition IMB_imbuf.hh:213
@ IMB_BLEND_COLOR
Definition IMB_imbuf.hh:209
@ IMB_BLEND_LINEARLIGHT
Definition IMB_imbuf.hh:203
@ IMB_BLEND_COPY_ALPHA
Definition IMB_imbuf.hh:214
@ IMB_BLEND_PINLIGHT
Definition IMB_imbuf.hh:201
@ IMB_BLEND_MIX
Definition IMB_imbuf.hh:186
@ IMB_BLEND_COPY
Definition IMB_imbuf.hh:212
@ IMB_BLEND_INTERPOLATE
Definition IMB_imbuf.hh:210
@ IMB_BLEND_ADD
Definition IMB_imbuf.hh:187
@ IMB_BLEND_SUB
Definition IMB_imbuf.hh:188
@ IMB_BLEND_LINEARBURN
Definition IMB_imbuf.hh:197
size_t IMB_get_pixel_count(const ImBuf *ibuf)
Get the length of the data of the given image buffer in pixels.
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr int64_t first() const
constexpr int64_t size() const
uint col
#define MEM_reallocN(vmemh, len)
BLI_INLINE float fb(float length, float L)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
static void rect_realloc_16bytes(void **buf_p, const uint size[2])
Definition rectop.cc:280
void IMB_rectfill_alpha(ImBuf *ibuf, const float value)
Definition rectop.cc:1195
static void rect_crop_4bytes(void **buf_p, const int size_src[2], const rcti *crop)
Definition rectop.cc:208
static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *crop)
Definition rectop.cc:225
void IMB_rectfill_area_replace(const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
Definition rectop.cc:1011
void buf_rectfill_area(uchar *rect, float *rectf, int width, int height, const float col[4], const ColorManagedDisplay *display, int x1, int y1, int x2, int y2)
Definition rectop.cc:1058
void IMB_rectblend_threaded(ImBuf *dbuf, const ImBuf *obuf, const ImBuf *sbuf, ushort *dmask, const ushort *curvemask, const ushort *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate)
Definition rectop.cc:939
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
Definition rectop.cc:242
void IMB_rectblend(ImBuf *dbuf, const ImBuf *obuf, const ImBuf *sbuf, ushort *dmask, const ushort *curvemask, const ushort *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate)
Definition rectop.cc:476
void(*)(uchar *dst, const uchar *src1, const uchar *src2) IMB_blend_func
Definition rectop.cc:473
void IMB_rectclip(ImBuf *dbuf, const ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
Definition rectop.cc:308
static void imb_rectclip3(ImBuf *dbuf, const ImBuf *obuf, const ImBuf *sbuf, int *destx, int *desty, int *origx, int *origy, int *srcx, int *srcy, int *width, int *height)
Definition rectop.cc:362
void IMB_blend_color_byte(uchar dst[4], const uchar src1[4], const uchar src2[4], IMB_BlendMode mode)
Definition rectop.cc:29
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition rectop.cc:117
void IMB_rectfill(ImBuf *drect, const float col[4])
Definition rectop.cc:979
void(*)(float *dst, const float *src1, const float *src2) IMB_blend_func_float
Definition rectop.cc:474
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
Definition rectop.cc:289
static void rect_realloc_4bytes(void **buf_p, const uint size[2])
Definition rectop.cc:271
void IMB_rectcpy(ImBuf *dbuf, const ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
Definition rectop.cc:445
void IMB_rectfill_area(ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, const ColorManagedDisplay *display)
Definition rectop.cc:1172
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230