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