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