Blender V4.5
filter.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 <cmath>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_base.h"
14#include "BLI_utildefines.h"
15
16#include "IMB_filter.hh"
17#include "IMB_imbuf.hh"
18#include "IMB_imbuf_types.hh"
19
20static void filtcolum(uchar *point, int y, int skip)
21{
22 uint c1, c2, c3, error;
23 uchar *point2;
24
25 if (y > 1) {
26 c1 = c2 = *point;
27 point2 = point;
28 error = 2;
29 for (y--; y > 0; y--) {
30 point2 += skip;
31 c3 = *point2;
32 c1 += (c2 << 1) + c3 + error;
33 error = c1 & 3;
34 *point = c1 >> 2;
35 point = point2;
36 c1 = c2;
37 c2 = c3;
38 }
39 *point = (c1 + (c2 << 1) + c2 + error) >> 2;
40 }
41}
42
43static void filtcolumf(float *point, int y, int skip)
44{
45 float c1, c2, c3, *point2;
46
47 if (y > 1) {
48 c1 = c2 = *point;
49 point2 = point;
50 for (y--; y > 0; y--) {
51 point2 += skip;
52 c3 = *point2;
53 c1 += (c2 * 2) + c3;
54 *point = 0.25f * c1;
55 point = point2;
56 c1 = c2;
57 c2 = c3;
58 }
59 *point = 0.25f * (c1 + (c2 * 2) + c2);
60 }
61}
62
63void IMB_filtery(ImBuf *ibuf)
64{
65 uchar *point = ibuf->byte_buffer.data;
66 float *pointf = ibuf->float_buffer.data;
67
68 int x = ibuf->x;
69 int y = ibuf->y;
70 int skip = x << 2;
71
72 for (; x > 0; x--) {
73 if (point) {
74 if (ibuf->planes > 24) {
75 filtcolum(point, y, skip);
76 }
77 point++;
78 filtcolum(point, y, skip);
79 point++;
80 filtcolum(point, y, skip);
81 point++;
82 filtcolum(point, y, skip);
83 point++;
84 }
85 if (pointf) {
86 if (ibuf->planes > 24) {
87 filtcolumf(pointf, y, skip);
88 }
89 pointf++;
90 filtcolumf(pointf, y, skip);
91 pointf++;
92 filtcolumf(pointf, y, skip);
93 pointf++;
94 filtcolumf(pointf, y, skip);
95 pointf++;
96 }
97 }
98}
99
100static void imb_filterN(ImBuf *out, ImBuf *in)
101{
102 BLI_assert(out->channels == in->channels);
103 BLI_assert(out->x == in->x && out->y == in->y);
104
105 const int channels = in->channels;
106 const int rowlen = in->x;
107
108 if (in->byte_buffer.data && out->byte_buffer.data) {
109 for (int y = 0; y < in->y; y++) {
110 /* setup rows */
111 const char *row2 = (const char *)in->byte_buffer.data + y * channels * rowlen;
112 const char *row1 = (y == 0) ? row2 : row2 - channels * rowlen;
113 const char *row3 = (y == in->y - 1) ? row2 : row2 + channels * rowlen;
114
115 char *cp = (char *)out->byte_buffer.data + y * channels * rowlen;
116
117 for (int x = 0; x < rowlen; x++) {
118 const char *r11, *r13, *r21, *r23, *r31, *r33;
119
120 if (x == 0) {
121 r11 = row1;
122 r21 = row2;
123 r31 = row3;
124 }
125 else {
126 r11 = row1 - channels;
127 r21 = row2 - channels;
128 r31 = row3 - channels;
129 }
130
131 if (x == rowlen - 1) {
132 r13 = row1;
133 r23 = row2;
134 r33 = row3;
135 }
136 else {
137 r13 = row1 + channels;
138 r23 = row2 + channels;
139 r33 = row3 + channels;
140 }
141
142 cp[0] = (r11[0] + 2 * row1[0] + r13[0] + 2 * r21[0] + 4 * row2[0] + 2 * r23[0] + r31[0] +
143 2 * row3[0] + r33[0]) >>
144 4;
145 cp[1] = (r11[1] + 2 * row1[1] + r13[1] + 2 * r21[1] + 4 * row2[1] + 2 * r23[1] + r31[1] +
146 2 * row3[1] + r33[1]) >>
147 4;
148 cp[2] = (r11[2] + 2 * row1[2] + r13[2] + 2 * r21[2] + 4 * row2[2] + 2 * r23[2] + r31[2] +
149 2 * row3[2] + r33[2]) >>
150 4;
151 cp[3] = (r11[3] + 2 * row1[3] + r13[3] + 2 * r21[3] + 4 * row2[3] + 2 * r23[3] + r31[3] +
152 2 * row3[3] + r33[3]) >>
153 4;
154 cp += channels;
155 row1 += channels;
156 row2 += channels;
157 row3 += channels;
158 }
159 }
160 }
161
162 if (in->float_buffer.data && out->float_buffer.data) {
163 for (int y = 0; y < in->y; y++) {
164 /* setup rows */
165 const float *row2 = (const float *)in->float_buffer.data + y * channels * rowlen;
166 const float *row1 = (y == 0) ? row2 : row2 - channels * rowlen;
167 const float *row3 = (y == in->y - 1) ? row2 : row2 + channels * rowlen;
168
169 float *cp = out->float_buffer.data + y * channels * rowlen;
170
171 for (int x = 0; x < rowlen; x++) {
172 const float *r11, *r13, *r21, *r23, *r31, *r33;
173
174 if (x == 0) {
175 r11 = row1;
176 r21 = row2;
177 r31 = row3;
178 }
179 else {
180 r11 = row1 - channels;
181 r21 = row2 - channels;
182 r31 = row3 - channels;
183 }
184
185 if (x == rowlen - 1) {
186 r13 = row1;
187 r23 = row2;
188 r33 = row3;
189 }
190 else {
191 r13 = row1 + channels;
192 r23 = row2 + channels;
193 r33 = row3 + channels;
194 }
195
196 cp[0] = (r11[0] + 2 * row1[0] + r13[0] + 2 * r21[0] + 4 * row2[0] + 2 * r23[0] + r31[0] +
197 2 * row3[0] + r33[0]) *
198 (1.0f / 16.0f);
199 cp[1] = (r11[1] + 2 * row1[1] + r13[1] + 2 * r21[1] + 4 * row2[1] + 2 * r23[1] + r31[1] +
200 2 * row3[1] + r33[1]) *
201 (1.0f / 16.0f);
202 cp[2] = (r11[2] + 2 * row1[2] + r13[2] + 2 * r21[2] + 4 * row2[2] + 2 * r23[2] + r31[2] +
203 2 * row3[2] + r33[2]) *
204 (1.0f / 16.0f);
205 cp[3] = (r11[3] + 2 * row1[3] + r13[3] + 2 * r21[3] + 4 * row2[3] + 2 * r23[3] + r31[3] +
206 2 * row3[3] + r33[3]) *
207 (1.0f / 16.0f);
208 cp += channels;
209 row1 += channels;
210 row2 += channels;
211 row3 += channels;
212 }
213 }
214 }
215}
216
217void IMB_mask_filter_extend(char *mask, int width, int height)
218{
219 const char *row1, *row2, *row3;
220 int rowlen, x, y;
221 char *temprect;
222
223 rowlen = width;
224
225 /* make a copy, to prevent flooding */
226 temprect = static_cast<char *>(MEM_dupallocN(mask));
227
228 for (y = 1; y <= height; y++) {
229 /* setup rows */
230 row1 = (char *)(temprect + (y - 2) * rowlen);
231 row2 = row1 + rowlen;
232 row3 = row2 + rowlen;
233 if (y == 1) {
234 row1 = row2;
235 }
236 else if (y == height) {
237 row3 = row2;
238 }
239
240 for (x = 0; x < rowlen; x++) {
241 if (mask[((y - 1) * rowlen) + x] == 0) {
242 if (*row1 || *row2 || *row3 || *(row1 + 1) || *(row3 + 1)) {
243 mask[((y - 1) * rowlen) + x] = FILTER_MASK_MARGIN;
244 }
245 else if ((x != rowlen - 1) && (*(row1 + 2) || *(row2 + 2) || *(row3 + 2))) {
246 mask[((y - 1) * rowlen) + x] = FILTER_MASK_MARGIN;
247 }
248 }
249
250 if (x != 0) {
251 row1++;
252 row2++;
253 row3++;
254 }
255 }
256 }
257
258 MEM_freeN(temprect);
259}
260
261void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val)
262{
263 int x, y;
264 if (ibuf->float_buffer.data) {
265 for (x = 0; x < ibuf->x; x++) {
266 for (y = 0; y < ibuf->y; y++) {
267 if (mask[ibuf->x * y + x] == val) {
268 float *col = ibuf->float_buffer.data + 4 * (ibuf->x * y + x);
269 col[0] = col[1] = col[2] = col[3] = 0.0f;
270 }
271 }
272 }
273 }
274 else {
275 /* char buffer */
276 for (x = 0; x < ibuf->x; x++) {
277 for (y = 0; y < ibuf->y; y++) {
278 if (mask[ibuf->x * y + x] == val) {
279 char *col = (char *)(ibuf->byte_buffer.data + 4 * ibuf->x * y + x);
280 col[0] = col[1] = col[2] = col[3] = 0;
281 }
282 }
283 }
284 }
285}
286
287static int filter_make_index(const int x, const int y, const int w, const int h)
288{
289 if (x < 0 || x >= w || y < 0 || y >= h) {
290 return -1; /* return bad index */
291 }
292
293 return y * w + x;
294}
295
297 const void *buffer, const char *mask, const int index, const int depth, const bool is_float)
298{
299 int res = 0;
300
301 if (index >= 0) {
302 const int alpha_index = depth * index + (depth - 1);
303
304 if (mask != nullptr) {
305 res = mask[index] != 0 ? 1 : 0;
306 }
307 else if ((is_float && ((const float *)buffer)[alpha_index] != 0.0f) ||
308 (!is_float && ((const uchar *)buffer)[alpha_index] != 0))
309 {
310 res = 1;
311 }
312 }
313
314 return res;
315}
316
317void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
318{
319 const int width = ibuf->x;
320 const int height = ibuf->y;
321 const int depth = 4; /* always 4 channels */
322 const int chsize = ibuf->float_buffer.data ? sizeof(float) : sizeof(uchar);
323 const size_t bsize = size_t(width) * height * depth * chsize;
324 const bool is_float = (ibuf->float_buffer.data != nullptr);
325 void *dstbuf = MEM_dupallocN(ibuf->float_buffer.data ? (void *)ibuf->float_buffer.data :
326 (void *)ibuf->byte_buffer.data);
327 char *dstmask = mask == nullptr ? nullptr : (char *)MEM_dupallocN(mask);
328 void *srcbuf = ibuf->float_buffer.data ? (void *)ibuf->float_buffer.data :
329 (void *)ibuf->byte_buffer.data;
330 char *srcmask = mask;
331 int cannot_early_out = 1, r, n, k, i, j, c;
332 float weight[25];
333
334 /* build a weights buffer */
335 n = 1;
336
337#if 0
338 k = 0;
339 for (i = -n; i <= n; i++) {
340 for (j = -n; j <= n; j++) {
341 weight[k++] = sqrt(float(i) * i + j * j);
342 }
343 }
344#endif
345
346 weight[0] = 1;
347 weight[1] = 2;
348 weight[2] = 1;
349 weight[3] = 2;
350 weight[4] = 0;
351 weight[5] = 2;
352 weight[6] = 1;
353 weight[7] = 2;
354 weight[8] = 1;
355
356 /* run passes */
357 for (r = 0; cannot_early_out == 1 && r < filter; r++) {
358 int x, y;
359 cannot_early_out = 0;
360
361 for (y = 0; y < height; y++) {
362 for (x = 0; x < width; x++) {
363 const int index = filter_make_index(x, y, width, height);
364
365 /* only update unassigned pixels */
366 if (!check_pixel_assigned(srcbuf, srcmask, index, depth, is_float)) {
367 float tmp[4];
368 float wsum = 0;
369 float acc[4] = {0, 0, 0, 0};
370 k = 0;
371
373 srcbuf, srcmask, filter_make_index(x - 1, y, width, height), depth, is_float) ||
375 srcbuf, srcmask, filter_make_index(x + 1, y, width, height), depth, is_float) ||
377 srcbuf, srcmask, filter_make_index(x, y - 1, width, height), depth, is_float) ||
379 srcbuf, srcmask, filter_make_index(x, y + 1, width, height), depth, is_float))
380 {
381 for (i = -n; i <= n; i++) {
382 for (j = -n; j <= n; j++) {
383 if (i != 0 || j != 0) {
384 const int tmpindex = filter_make_index(x + i, y + j, width, height);
385
386 if (check_pixel_assigned(srcbuf, srcmask, tmpindex, depth, is_float)) {
387 if (is_float) {
388 for (c = 0; c < depth; c++) {
389 tmp[c] = ((const float *)srcbuf)[depth * tmpindex + c];
390 }
391 }
392 else {
393 for (c = 0; c < depth; c++) {
394 tmp[c] = float(((const uchar *)srcbuf)[depth * tmpindex + c]);
395 }
396 }
397
398 wsum += weight[k];
399
400 for (c = 0; c < depth; c++) {
401 acc[c] += weight[k] * tmp[c];
402 }
403 }
404 }
405 k++;
406 }
407 }
408
409 if (wsum != 0) {
410 for (c = 0; c < depth; c++) {
411 acc[c] /= wsum;
412 }
413
414 if (is_float) {
415 for (c = 0; c < depth; c++) {
416 ((float *)dstbuf)[depth * index + c] = acc[c];
417 }
418 }
419 else {
420 for (c = 0; c < depth; c++) {
421 ((uchar *)dstbuf)[depth * index + c] = acc[c] > 255 ?
422 255 :
423 (acc[c] < 0 ? 0 :
424 uchar(roundf(acc[c])));
425 }
426 }
427
428 if (dstmask != nullptr) {
429 dstmask[index] = FILTER_MASK_MARGIN; /* assigned */
430 }
431 cannot_early_out = 1;
432 }
433 }
434 }
435 }
436 }
437
438 /* keep the original buffer up to date. */
439 memcpy(srcbuf, dstbuf, bsize);
440 if (dstmask != nullptr) {
441 memcpy(srcmask, dstmask, size_t(width) * height);
442 }
443 }
444
445 /* free memory */
446 MEM_freeN(dstbuf);
447 if (dstmask != nullptr) {
448 MEM_freeN(dstmask);
449 }
450}
451
452void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
453{
454 ImBuf *hbuf = ibuf;
455 int curmap = 0;
456
457 ibuf->miptot = 1;
458
459 while (curmap < IMB_MIPMAP_LEVELS) {
460
461 if (ibuf->mipmap[curmap]) {
462
463 if (use_filter) {
464 ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, hbuf->planes, hbuf->flags);
465 imb_filterN(nbuf, hbuf);
466 imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
467 IMB_freeImBuf(nbuf);
468 }
469 else {
470 imb_onehalf_no_alloc(ibuf->mipmap[curmap], hbuf);
471 }
472 }
473
474 ibuf->miptot = curmap + 2;
475 hbuf = ibuf->mipmap[curmap];
476 if (hbuf) {
477 hbuf->miplevel = curmap + 1;
478 }
479
480 if (!hbuf || (hbuf->x <= 2 && hbuf->y <= 2)) {
481 break;
482 }
483
484 curmap++;
485 }
486}
487
488void IMB_makemipmap(ImBuf *ibuf, int use_filter)
489{
490 ImBuf *hbuf = ibuf;
491 int curmap = 0;
492
493 IMB_free_mipmaps(ibuf);
494
495 /* no mipmap for non RGBA images */
496 if (ibuf->float_buffer.data && ibuf->channels < 4) {
497 return;
498 }
499
500 ibuf->miptot = 1;
501
502 while (curmap < IMB_MIPMAP_LEVELS) {
503 if (use_filter) {
504 ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, hbuf->planes, hbuf->flags);
505 imb_filterN(nbuf, hbuf);
506 ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
507 IMB_freeImBuf(nbuf);
508 }
509 else {
510 ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
511 }
512
513 ibuf->miptot = curmap + 2;
514 hbuf = ibuf->mipmap[curmap];
515 hbuf->miplevel = curmap + 1;
516
517 if (hbuf->x < 2 && hbuf->y < 2) {
518 break;
519 }
520
521 curmap++;
522 }
523}
524
525ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
526{
527 CLAMP(level, 0, ibuf->miptot - 1);
528 return (level == 0) ? ibuf : ibuf->mipmap[level - 1];
529}
530
531void IMB_premultiply_rect(uint8_t *rect, char planes, int w, int h)
532{
533 uint8_t *cp;
534 int x, y, val;
535
536 if (planes == 24) { /* put alpha at 255 */
537 cp = rect;
538
539 for (y = 0; y < h; y++) {
540 for (x = 0; x < w; x++, cp += 4) {
541 cp[3] = 255;
542 }
543 }
544 }
545 else {
546 cp = rect;
547
548 for (y = 0; y < h; y++) {
549 for (x = 0; x < w; x++, cp += 4) {
550 val = cp[3];
551 cp[0] = (cp[0] * val) >> 8;
552 cp[1] = (cp[1] * val) >> 8;
553 cp[2] = (cp[2] * val) >> 8;
554 }
555 }
556 }
557}
558
559void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
560{
561 float val, *cp;
562 int x, y;
563
564 if (channels == 4) {
565 cp = rect_float;
566 for (y = 0; y < h; y++) {
567 for (x = 0; x < w; x++, cp += 4) {
568 val = cp[3];
569 cp[0] = cp[0] * val;
570 cp[1] = cp[1] * val;
571 cp[2] = cp[2] * val;
572 }
573 }
574 }
575}
576
578{
579 if (ibuf == nullptr) {
580 return;
581 }
582
583 if (ibuf->byte_buffer.data) {
584 IMB_premultiply_rect(ibuf->byte_buffer.data, ibuf->planes, ibuf->x, ibuf->y);
585 }
586
587 if (ibuf->float_buffer.data) {
588 IMB_premultiply_rect_float(ibuf->float_buffer.data, ibuf->channels, ibuf->x, ibuf->y);
589 }
590}
591
592void IMB_unpremultiply_rect(uint8_t *rect, char planes, int w, int h)
593{
594 uchar *cp;
595 int x, y;
596 float val;
597
598 if (planes == 24) { /* put alpha at 255 */
599 cp = rect;
600
601 for (y = 0; y < h; y++) {
602 for (x = 0; x < w; x++, cp += 4) {
603 cp[3] = 255;
604 }
605 }
606 }
607 else {
608 cp = rect;
609
610 for (y = 0; y < h; y++) {
611 for (x = 0; x < w; x++, cp += 4) {
612 val = cp[3] != 0 ? 1.0f / float(cp[3]) : 1.0f;
613 cp[0] = unit_float_to_uchar_clamp(cp[0] * val);
614 cp[1] = unit_float_to_uchar_clamp(cp[1] * val);
615 cp[2] = unit_float_to_uchar_clamp(cp[2] * val);
616 }
617 }
618 }
619}
620
621void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
622{
623 float val, *fp;
624 int x, y;
625
626 if (channels == 4) {
627 fp = rect_float;
628 for (y = 0; y < h; y++) {
629 for (x = 0; x < w; x++, fp += 4) {
630 val = fp[3] != 0.0f ? 1.0f / fp[3] : 1.0f;
631 fp[0] = fp[0] * val;
632 fp[1] = fp[1] * val;
633 fp[2] = fp[2] * val;
634 }
635 }
636 }
637}
638
640{
641 if (ibuf == nullptr) {
642 return;
643 }
644
645 if (ibuf->byte_buffer.data) {
646 IMB_unpremultiply_rect(ibuf->byte_buffer.data, ibuf->planes, ibuf->x, ibuf->y);
647 }
648
649 if (ibuf->float_buffer.data) {
650 IMB_unpremultiply_rect_float(ibuf->float_buffer.data, ibuf->channels, ibuf->x, ibuf->y);
651 }
652}
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
Function declarations for filter.cc.
void imb_onehalf_no_alloc(ImBuf *ibuf2, ImBuf *ibuf1)
Definition scaling.cc:235
ImBuf * IMB_onehalf(ImBuf *ibuf1)
Definition scaling.cc:313
#define FILTER_MASK_MARGIN
Definition IMB_imbuf.hh:296
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_free_mipmaps(ImBuf *ibuf)
#define IMB_MIPMAP_LEVELS
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:577
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:621
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:559
void IMB_mask_filter_extend(char *mask, int width, int height)
Definition filter.cc:217
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
Definition filter.cc:488
static void imb_filterN(ImBuf *out, ImBuf *in)
Definition filter.cc:100
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
Definition filter.cc:452
void IMB_unpremultiply_alpha(ImBuf *ibuf)
Definition filter.cc:639
static void filtcolumf(float *point, int y, int skip)
Definition filter.cc:43
void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val)
Definition filter.cc:261
static void filtcolum(uchar *point, int y, int skip)
Definition filter.cc:20
void IMB_filtery(ImBuf *ibuf)
Definition filter.cc:63
void IMB_unpremultiply_rect(uint8_t *rect, char planes, int w, int h)
Definition filter.cc:592
void IMB_premultiply_rect(uint8_t *rect, char planes, int w, int h)
Definition filter.cc:531
void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
Definition filter.cc:317
ImBuf * IMB_getmipmap(ImBuf *ibuf, int level)
Definition filter.cc:525
static int filter_make_index(const int x, const int y, const int w, const int h)
Definition filter.cc:287
static int check_pixel_assigned(const void *buffer, const char *mask, const int index, const int depth, const bool is_float)
Definition filter.cc:296
uint col
#define in
#define out
#define filter
#define sqrt
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
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)
static void error(const char *str)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
i
Definition text_draw.cc:230