style cleanup: follow style guide for formatting of if/for/while loops, and else...
[blender.git] / source / blender / imbuf / intern / filter.c
index 16fb1fdf4aa982cd39702ae636c0111c57250150..a93f47db9a30901032c7df3004cb0b0f592dbc4d 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ *
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): none yet.
+ * Contributor(s): Morten Mikkelsen.
  *
  * ***** END GPL LICENSE BLOCK *****
  * filter.c
  *
- * $Id$
  */
 
 /** \file blender/imbuf/intern/filter.c
@@ -54,10 +54,10 @@ static void filtrow(unsigned char *point, int x)
 {
        unsigned int c1,c2,c3,error;
 
-       if (x>1){
+       if (x>1) {
                c1 = c2 = *point;
                error = 2;
-               for(x--;x>0;x--){
+               for (x--;x>0;x--) {
                        c3 = point[4];
                        c1 += (c2<<1) + c3 + error;
                        error = c1 & 3;
@@ -74,9 +74,9 @@ static void filtrowf(float *point, int x)
 {
        float c1,c2,c3;
        
-       if (x>1){
+       if (x>1) {
                c1 = c2 = *point;
-               for(x--;x>0;x--){
+               for (x--;x>0;x--) {
                        c3 = point[4];
                        c1 += (c2 * 2) + c3;
                        *point = 0.25f*c1;
@@ -95,11 +95,11 @@ static void filtcolum(unsigned char *point, int y, int skip)
        unsigned int c1,c2,c3,error;
        unsigned char *point2;
 
-       if (y>1){
+       if (y>1) {
                c1 = c2 = *point;
                point2 = point;
                error = 2;
-               for(y--;y>0;y--){
+               for (y--;y>0;y--) {
                        point2 += skip;
                        c3 = *point2;
                        c1 += (c2<<1) + c3 +error;
@@ -117,10 +117,10 @@ static void filtcolumf(float *point, int y, int skip)
 {
        float c1,c2,c3, *point2;
        
-       if (y>1){
+       if (y>1) {
                c1 = c2 = *point;
                point2 = point;
-               for(y--;y>0;y--){
+               for (y--;y>0;y--) {
                        point2 += skip;
                        c3 = *point2;
                        c1 += (c2 * 2) + c3;
@@ -146,9 +146,9 @@ void IMB_filtery(struct ImBuf *ibuf)
        y = ibuf->y;
        skip = x<<2;
 
-       for (;x>0;x--){
+       for (;x>0;x--) {
                if (point) {
-                       if (ibuf->depth > 24) filtcolum(point,y,skip);
+                       if (ibuf->planes > 24) filtcolum(point,y,skip);
                        point++;
                        filtcolum(point,y,skip);
                        point++;
@@ -158,7 +158,7 @@ void IMB_filtery(struct ImBuf *ibuf)
                        point++;
                }
                if (pointf) {
-                       if (ibuf->depth > 24) filtcolumf(pointf,y,skip);
+                       if (ibuf->planes > 24) filtcolumf(pointf,y,skip);
                        pointf++;
                        filtcolumf(pointf,y,skip);
                        pointf++;
@@ -184,9 +184,9 @@ void imb_filterx(struct ImBuf *ibuf)
        y = ibuf->y;
        skip = (x<<2) - 3;
 
-       for (;y>0;y--){
+       for (;y>0;y--) {
                if (point) {
-                       if (ibuf->depth > 24) filtrow(point,x);
+                       if (ibuf->planes > 24) filtrow(point,x);
                        point++;
                        filtrow(point,x);
                        point++;
@@ -196,7 +196,7 @@ void imb_filterx(struct ImBuf *ibuf)
                        point+=skip;
                }
                if (pointf) {
-                       if (ibuf->depth > 24) filtrowf(pointf,x);
+                       if (ibuf->planes > 24) filtrowf(pointf,x);
                        pointf++;
                        filtrowf(pointf,x);
                        pointf++;
@@ -216,7 +216,7 @@ void IMB_filterN(ImBuf *out, ImBuf *in)
        
        rowlen= in->x;
        
-       for(y=0; y<in->y; y++) {
+       for (y=0; y<in->y; y++) {
                /* setup rows */
                row2= (char*)(in->rect + y*rowlen);
                row1= (y == 0)? row2: row2 - 4*rowlen;
@@ -224,8 +224,8 @@ void IMB_filterN(ImBuf *out, ImBuf *in)
                
                cp= (char *)(out->rect + y*rowlen);
                
-               for(x=0; x<rowlen; x++) {
-                       if(x == 0) {
+               for (x=0; x<rowlen; x++) {
+                       if (x == 0) {
                                r11 = row1;
                                r21 = row1;
                                r31 = row1;
@@ -236,7 +236,7 @@ void IMB_filterN(ImBuf *out, ImBuf *in)
                                r31 = row1-4;
                        }
 
-                       if(x == rowlen-1) {
+                       if (x == rowlen-1) {
                                r13 = row1;
                                r23 = row1;
                                r33 = row1;
@@ -262,121 +262,205 @@ void IMB_filter(struct ImBuf *ibuf)
        imb_filterx(ibuf);
 }
 
-#define EXTEND_PIXEL(color, w) if((color)[3]) {r+= w*(color)[0]; g+= w*(color)[1]; b+= w*(color)[2]; a+= w*(color)[3]; tot+=w;}
-
-/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
- * 
- * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
- * */
-void IMB_filter_extend(struct ImBuf *ibuf, char *mask)
+void IMB_mask_filter_extend(char *mask, int width, int height)
 {
-       register char *row1, *row2, *row3;
-       register char *cp; 
+       char *row1, *row2, *row3;
        int rowlen, x, y;
-       
-       rowlen= ibuf->x;
-       
-       
+       char *temprect;
+
+       rowlen= width;
+
+       /* make a copy, to prevent flooding */
+       temprect= MEM_dupallocN(mask);
+
+       for (y=1; y<=height; y++) {
+               /* setup rows */
+               row1= (char *)(temprect + (y-2)*rowlen);
+               row2= row1 + rowlen;
+               row3= row2 + rowlen;
+               if (y==1)
+                       row1= row2;
+               else if (y==height)
+                       row3= row2;
+
+               for (x=0; x<rowlen; x++) {
+                       if (mask[((y-1)*rowlen)+x]==0) {
+                               if (*row1 || *row2 || *row3 || *(row1+1) || *(row3+1) ) {
+                                       mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
+                               }
+                               else if ((x!=rowlen-1) && (*(row1+2) || *(row2+2) || *(row3+2)) ) {
+                                       mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
+                               }
+                       }
+
+                       if (x!=0) {
+                               row1++; row2++; row3++;
+                       }
+               }
+       }
+
+       MEM_freeN(temprect);
+}
+
+void IMB_mask_clear(ImBuf *ibuf, char *mask, int val)
+{
+       int x,y;
        if (ibuf->rect_float) {
-               float *temprect;
-               float *row1f, *row2f, *row3f;
-               float *fp;
-               temprect= MEM_dupallocN(ibuf->rect_float);
-               
-               for(y=1; y<=ibuf->y; y++) {
-                       /* setup rows */
-                       row1f= (float *)(temprect + (y-2)*rowlen*4);
-                       row2f= row1f + 4*rowlen;
-                       row3f= row2f + 4*rowlen;
-                       if(y==1)
-                               row1f= row2f;
-                       else if(y==ibuf->y)
-                               row3f= row2f;
-                       
-                       fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4);
-                               
-                       for(x=0; x<rowlen; x++) {
-                               if((mask==NULL && fp[3]==0.0f) || (mask && mask[((y-1)*rowlen)+x]==1)) {
-                                       int tot= 0;
-                                       float r=0.0f, g=0.0f, b=0.0f, a=0.0f;
-                                       
-                                       EXTEND_PIXEL(row1f, 1);
-                                       EXTEND_PIXEL(row2f, 2);
-                                       EXTEND_PIXEL(row3f, 1);
-                                       EXTEND_PIXEL(row1f+4, 2);
-                                       EXTEND_PIXEL(row3f+4, 2);
-                                       if(x!=rowlen-1) {
-                                               EXTEND_PIXEL(row1f+8, 1);
-                                               EXTEND_PIXEL(row2f+8, 2);
-                                               EXTEND_PIXEL(row3f+8, 1);
-                                       }                                       
-                                       if(tot) {
-                                               fp[0]= r/tot;
-                                               fp[1]= g/tot;
-                                               fp[2]= b/tot;
-                                               fp[3]= a/tot;
-                                       }
+               for (x=0; x<ibuf->x; x++) {
+                       for (y=0; y<ibuf->y; y++) {
+                               if (mask[ibuf->x*y + x] == val) {
+                                       float *col= ibuf->rect_float + 4*(ibuf->x*y + x);
+                                       col[0] = col[1] = col[2] = col[3] = 0.0f;
                                }
-                               fp+=4; 
-                               
-                               if(x!=0) {
-                                       row1f+=4; row2f+=4; row3f+=4;
+                       }
+               }
+       }
+       else {
+               /* char buffer */
+               for (x=0; x<ibuf->x; x++) {
+                       for (y=0; y<ibuf->y; y++) {
+                               if (mask[ibuf->x*y + x] == val) {
+                                       char *col= (char *)(ibuf->rect + ibuf->x*y + x);
+                                       col[0] = col[1] = col[2] = col[3] = 0;
                                }
                        }
                }
+       }
+}
+
+static int filter_make_index(const int x, const int y, const int w, const int h)
+{
+       if (x<0 || x>=w || y<0 || y>=h) return -1;      /* return bad index */
+       else return y*w+x;
+}
 
-               MEM_freeN(temprect);
+static int check_pixel_assigned(const void *buffer, const char *mask, const int index, const int depth, const int is_float)
+{
+       int res = 0;
+
+       if (index>=0) {
+               const int alpha_index = depth*index+(depth-1);
+
+               if (mask!=NULL) {
+                       res = mask[index]!=0 ? 1 : 0;
+               }
+               else if ( (is_float && ((const float *) buffer)[alpha_index]!=0.0f) ||
+                               (!is_float && ((const unsigned char *) buffer)[alpha_index]!=0) ) {
+                       res=1;
+               }
        }
-       else if(ibuf->rect) {
-               int *temprect;
-               
-               /* make a copy, to prevent flooding */
-               temprect= MEM_dupallocN(ibuf->rect);
-               
-               for(y=1; y<=ibuf->y; y++) {
-                       /* setup rows */
-                       row1= (char *)(temprect + (y-2)*rowlen);
-                       row2= row1 + 4*rowlen;
-                       row3= row2 + 4*rowlen;
-                       if(y==1)
-                               row1= row2;
-                       else if(y==ibuf->y)
-                               row3= row2;
-                       
-                       cp= (char *)(ibuf->rect + (y-1)*rowlen);
-                       
-                       for(x=0; x<rowlen; x++) {
-                               /*if(cp[3]==0) {*/
-                               if((mask==NULL && cp[3]==0) || (mask && mask[((y-1)*rowlen)+x]==1)) {
-                                       int tot= 0, r=0, g=0, b=0, a=0;
-                                       
-                                       EXTEND_PIXEL(row1, 1);
-                                       EXTEND_PIXEL(row2, 2);
-                                       EXTEND_PIXEL(row3, 1);
-                                       EXTEND_PIXEL(row1+4, 2);
-                                       EXTEND_PIXEL(row3+4, 2);
-                                       if(x!=rowlen-1) {
-                                               EXTEND_PIXEL(row1+8, 1);
-                                               EXTEND_PIXEL(row2+8, 2);
-                                               EXTEND_PIXEL(row3+8, 1);
-                                       }                                       
-                                       if(tot) {
-                                               cp[0]= r/tot;
-                                               cp[1]= g/tot;
-                                               cp[2]= b/tot;
-                                               cp[3]= a/tot;
+
+       return res;
+}
+
+/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
+ * 
+ * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
+ * */
+void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
+{
+       const int width= ibuf->x;
+       const int height= ibuf->y;
+       const int depth= 4;             /* always 4 channels */
+       const int chsize= ibuf->rect_float ? sizeof(float) : sizeof(unsigned char);
+       const int bsize= width*height*depth*chsize;
+       const int is_float= ibuf->rect_float!=NULL;
+       void *dstbuf= (void *) MEM_dupallocN(ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect);
+       char *dstmask= mask==NULL ? NULL : (char *) MEM_dupallocN(mask);
+       void *srcbuf= ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect;
+       char *srcmask= mask;
+       int cannot_early_out= 1, r, n, k, i, j, c;
+       float weight[25];
+
+       /* build a weights buffer */
+       n= 1;
+
+#if 0
+       k= 0;
+       for (i = -n; i <= n; i++)
+               for (j = -n; j <= n; j++)
+                       weight[k++] = sqrt((float) i * i + j * j);
+#endif
+
+       weight[0]=1; weight[1]=2; weight[2]=1;
+       weight[3]=2; weight[4]=0; weight[5]=2;
+       weight[6]=1; weight[7]=2; weight[8]=1;
+
+       /* run passes */
+       for (r = 0; cannot_early_out == 1 && r < filter; r++) {
+               int x, y;
+               cannot_early_out = 0;
+
+               for (y= 0; y<height; y++) {
+                       for (x= 0; x<width; x++) {
+                               const int index= filter_make_index(x, y, width, height);
+
+                               /* only update unassigned pixels */
+                               if (!check_pixel_assigned(srcbuf, srcmask, index, depth, is_float)) {
+                                       float tmp[4];
+                                       float wsum=0;
+                                       float acc[4]={0,0,0,0};
+                                       k = 0;
+
+                                       if (check_pixel_assigned(srcbuf, srcmask, filter_make_index(x-1, y, width, height), depth, is_float) ||
+                                               check_pixel_assigned(srcbuf, srcmask, filter_make_index(x+1, y, width, height), depth, is_float) ||
+                                               check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y-1, width, height), depth, is_float) ||
+                                               check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y+1, width, height), depth, is_float)) {
+                                               for (i= -n; i<=n; i++) {
+                                                       for (j=-n; j<=n; j++) {
+                                                               if (i != 0 || j != 0) {
+                                                                       const int tmpindex= filter_make_index(x+i, y+j, width, height);
+
+                                                                       if (check_pixel_assigned(srcbuf, srcmask, tmpindex, depth, is_float))   {
+                                                                               if (is_float) {
+                                                                                       for (c=0; c<depth; c++)
+                                                                                               tmp[c] = ((const float *) srcbuf)[depth*tmpindex+c];
+                                                                               }
+                                                                               else {
+                                                                                       for (c=0; c<depth; c++)
+                                                                                               tmp[c] = (float) ((const unsigned char *) srcbuf)[depth*tmpindex+c];
+                                                                               }
+
+                                                                               wsum+= weight[k];
+
+                                                                               for (c=0; c<depth; c++)
+                                                                                       acc[c]+= weight[k] * tmp[c];
+                                                                       }
+                                                               }
+                                                               k++;
+                                                       }
+                                               }
+
+                                               if (wsum!=0) {
+                                                       for (c=0; c<depth; c++)
+                                                               acc[c]/= wsum;
+
+                                                       if (is_float) {
+                                                               for (c=0; c<depth; c++)
+                                                                       ((float *) dstbuf)[depth*index+c] = acc[c];
+                                                       }
+                                                       else {
+                                                               for (c=0; c<depth; c++) {
+                                                                       ((unsigned char *) dstbuf)[depth*index+c]= acc[c] > 255 ? 255 : (acc[c] < 0 ? 0 : ((unsigned char) (acc[c]+0.5f)));
+                                                               }
+                                                       }
+
+                                                       if (dstmask!=NULL) dstmask[index]=FILTER_MASK_MARGIN;   /* assigned */
+                                                       cannot_early_out = 1;
+                                               }
                                        }
                                }
-                               cp+=4;
-                               
-                               if(x!=0) {
-                                       row1+=4; row2+=4; row3+=4;
-                               }
                        }
                }
-               
-               MEM_freeN(temprect);
+
+               /* keep the original buffer up to date. */
+               memcpy(srcbuf, dstbuf, bsize);
+               if (dstmask!=NULL) memcpy(srcmask, dstmask, width*height);
        }
+
+       /* free memory */
+       MEM_freeN(dstbuf);
+       if (dstmask!=NULL) MEM_freeN(dstmask);
 }
 
 /* threadsafe version, only recreates existing maps */
@@ -389,9 +473,9 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
        
        while(curmap < IB_MIPMAP_LEVELS) {
                
-               if(ibuf->mipmap[curmap]) {
+               if (ibuf->mipmap[curmap]) {
                        
-                       if(use_filter) {
+                       if (use_filter) {
                                ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
                                IMB_filterN(nbuf, hbuf);
                                imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
@@ -403,10 +487,10 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
                
                ibuf->miptot= curmap+2;
                hbuf= ibuf->mipmap[curmap];
-               if(hbuf)
+               if (hbuf)
                        hbuf->miplevel= curmap+1;
                
-               if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
+               if (!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
                        break;
                
                curmap++;
@@ -424,7 +508,7 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
        ibuf->miptot= 1;
 
        while(curmap < IB_MIPMAP_LEVELS) {
-               if(use_filter) {
+               if (use_filter) {
                        ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
                        IMB_filterN(nbuf, hbuf);
                        ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
@@ -437,7 +521,7 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
                hbuf= ibuf->mipmap[curmap];
                hbuf->miplevel= curmap+1;
 
-               if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
+               if (hbuf->x <= 2 && hbuf->y <= 2)
                        break;
 
                curmap++;
@@ -450,23 +534,23 @@ ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
        return (level == 0)? ibuf: ibuf->mipmap[level-1];
 }
 
-void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
+void IMB_premultiply_rect(unsigned int *rect, char planes, int w, int h)
 {
        char *cp;
        int x, y, val;
 
-       if(depth == 24) {       /* put alpha at 255 */
+       if (planes == 24) {     /* put alpha at 255 */
                cp= (char *)(rect);
 
-               for(y=0; y<h; y++)
-                       for(x=0; x<w; x++, cp+=4)
+               for (y=0; y<h; y++)
+                       for (x=0; x<w; x++, cp+=4)
                                cp[3]= 255;
        }
        else {
                cp= (char *)(rect);
 
-               for(y=0; y<h; y++) {
-                       for(x=0; x<w; x++, cp+=4) {
+               for (y=0; y<h; y++) {
+                       for (x=0; x<w; x++, cp+=4) {
                                val= cp[3];
                                cp[0]= (cp[0]*val)>>8;
                                cp[1]= (cp[1]*val)>>8;
@@ -476,22 +560,22 @@ void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
        }
 }
 
-void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
+void IMB_premultiply_rect_float(float *rect_float, char planes, int w, int h)
 {
        float val, *cp;
        int x, y;
 
-       if(depth==24) { /* put alpha at 1.0 */
+       if (planes==24) {       /* put alpha at 1.0 */
                cp= rect_float;
 
-               for(y=0; y<h; y++)
-                       for(x=0; x<w; x++, cp+=4)
+               for (y=0; y<h; y++)
+                       for (x=0; x<w; x++, cp+=4)
                                cp[3]= 1.0;
        }
        else {
                cp= rect_float;
-               for(y=0; y<h; y++) {
-                       for(x=0; x<w; x++, cp+=4) {
+               for (y=0; y<h; y++) {
+                       for (x=0; x<w; x++, cp+=4) {
                                val= cp[3];
                                cp[0]= cp[0]*val;
                                cp[1]= cp[1]*val;
@@ -504,13 +588,13 @@ void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
 
 void IMB_premultiply_alpha(ImBuf *ibuf)
 {
-       if(ibuf==NULL)
+       if (ibuf==NULL)
                return;
 
-       if(ibuf->rect)
-               IMB_premultiply_rect(ibuf->rect, ibuf->depth, ibuf->x, ibuf->y);
+       if (ibuf->rect)
+               IMB_premultiply_rect(ibuf->rect, ibuf->planes, ibuf->x, ibuf->y);
 
-       if(ibuf->rect_float)
-               IMB_premultiply_rect_float(ibuf->rect_float, ibuf->depth, ibuf->x, ibuf->y);
+       if (ibuf->rect_float)
+               IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
 }