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