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