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