Blender V2.61 - r43446

filter.c

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Morten Mikkelsen.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  * filter.c
00029  *
00030  */
00031 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "BLI_utildefines.h"
00040 
00041 
00042 
00043 #include "IMB_imbuf_types.h"
00044 #include "IMB_imbuf.h"
00045 #include "IMB_filter.h"
00046 
00047 #include "imbuf.h"
00048 
00049 /************************************************************************/
00050 /*              FILTERS                 */
00051 /************************************************************************/
00052 
00053 static void filtrow(unsigned char *point, int x)
00054 {
00055     unsigned int c1,c2,c3,error;
00056 
00057     if (x>1){
00058         c1 = c2 = *point;
00059         error = 2;
00060         for(x--;x>0;x--){
00061             c3 = point[4];
00062             c1 += (c2<<1) + c3 + error;
00063             error = c1 & 3;
00064             *point = c1 >> 2;
00065             point += 4;
00066             c1=c2;
00067             c2=c3;
00068         }
00069         *point = (c1 + (c2<<1) + c2 + error) >> 2;
00070     }
00071 }
00072 
00073 static void filtrowf(float *point, int x)
00074 {
00075     float c1,c2,c3;
00076     
00077     if (x>1){
00078         c1 = c2 = *point;
00079         for(x--;x>0;x--){
00080             c3 = point[4];
00081             c1 += (c2 * 2) + c3;
00082             *point = 0.25f*c1;
00083             point += 4;
00084             c1=c2;
00085             c2=c3;
00086         }
00087         *point = 0.25f*(c1 + (c2 * 2) + c2);
00088     }
00089 }
00090 
00091 
00092 
00093 static void filtcolum(unsigned char *point, int y, int skip)
00094 {
00095     unsigned int c1,c2,c3,error;
00096     unsigned char *point2;
00097 
00098     if (y>1){
00099         c1 = c2 = *point;
00100         point2 = point;
00101         error = 2;
00102         for(y--;y>0;y--){
00103             point2 += skip;
00104             c3 = *point2;
00105             c1 += (c2<<1) + c3 +error;
00106             error = c1 & 3;
00107             *point = c1 >> 2;
00108             point=point2;
00109             c1=c2;
00110             c2=c3;
00111         }
00112         *point = (c1 + (c2<<1) + c2 + error) >> 2;
00113     }
00114 }
00115 
00116 static void filtcolumf(float *point, int y, int skip)
00117 {
00118     float c1,c2,c3, *point2;
00119     
00120     if (y>1){
00121         c1 = c2 = *point;
00122         point2 = point;
00123         for(y--;y>0;y--){
00124             point2 += skip;
00125             c3 = *point2;
00126             c1 += (c2 * 2) + c3;
00127             *point = 0.25f*c1;
00128             point=point2;
00129             c1=c2;
00130             c2=c3;
00131         }
00132         *point = 0.25f*(c1 + (c2 * 2) + c2);
00133     }
00134 }
00135 
00136 void IMB_filtery(struct ImBuf *ibuf)
00137 {
00138     unsigned char *point;
00139     float *pointf;
00140     int x, y, skip;
00141 
00142     point = (unsigned char *)ibuf->rect;
00143     pointf = ibuf->rect_float;
00144 
00145     x = ibuf->x;
00146     y = ibuf->y;
00147     skip = x<<2;
00148 
00149     for (;x>0;x--){
00150         if (point) {
00151             if (ibuf->planes > 24) filtcolum(point,y,skip);
00152             point++;
00153             filtcolum(point,y,skip);
00154             point++;
00155             filtcolum(point,y,skip);
00156             point++;
00157             filtcolum(point,y,skip);
00158             point++;
00159         }
00160         if (pointf) {
00161             if (ibuf->planes > 24) filtcolumf(pointf,y,skip);
00162             pointf++;
00163             filtcolumf(pointf,y,skip);
00164             pointf++;
00165             filtcolumf(pointf,y,skip);
00166             pointf++;
00167             filtcolumf(pointf,y,skip);
00168             pointf++;
00169         }
00170     }
00171 }
00172 
00173 
00174 void imb_filterx(struct ImBuf *ibuf)
00175 {
00176     unsigned char *point;
00177     float *pointf;
00178     int x, y, skip;
00179 
00180     point = (unsigned char *)ibuf->rect;
00181     pointf = ibuf->rect_float;
00182 
00183     x = ibuf->x;
00184     y = ibuf->y;
00185     skip = (x<<2) - 3;
00186 
00187     for (;y>0;y--){
00188         if (point) {
00189             if (ibuf->planes > 24) filtrow(point,x);
00190             point++;
00191             filtrow(point,x);
00192             point++;
00193             filtrow(point,x);
00194             point++;
00195             filtrow(point,x);
00196             point+=skip;
00197         }
00198         if (pointf) {
00199             if (ibuf->planes > 24) filtrowf(pointf,x);
00200             pointf++;
00201             filtrowf(pointf,x);
00202             pointf++;
00203             filtrowf(pointf,x);
00204             pointf++;
00205             filtrowf(pointf,x);
00206             pointf+=skip;
00207         }
00208     }
00209 }
00210 
00211 void IMB_filterN(ImBuf *out, ImBuf *in)
00212 {
00213     register char *row1, *row2, *row3;
00214     register char *cp, *r11, *r13, *r21, *r23, *r31, *r33;
00215     int rowlen, x, y;
00216     
00217     rowlen= in->x;
00218     
00219     for(y=0; y<in->y; y++) {
00220         /* setup rows */
00221         row2= (char*)(in->rect + y*rowlen);
00222         row1= (y == 0)? row2: row2 - 4*rowlen;
00223         row3= (y == in->y-1)? row2: row2 + 4*rowlen;
00224         
00225         cp= (char *)(out->rect + y*rowlen);
00226         
00227         for(x=0; x<rowlen; x++) {
00228             if(x == 0) {
00229                 r11 = row1;
00230                 r21 = row1;
00231                 r31 = row1;
00232             }
00233             else {
00234                 r11 = row1-4;
00235                 r21 = row1-4;
00236                 r31 = row1-4;
00237             }
00238 
00239             if(x == rowlen-1) {
00240                 r13 = row1;
00241                 r23 = row1;
00242                 r33 = row1;
00243             }
00244             else {
00245                 r13 = row1+4;
00246                 r23 = row1+4;
00247                 r33 = row1+4;
00248             }
00249 
00250             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;
00251             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;
00252             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;
00253             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;
00254             cp+=4; row1+=4; row2+=4; row3+=4;
00255         }
00256     }
00257 }
00258 
00259 void IMB_filter(struct ImBuf *ibuf)
00260 {
00261     IMB_filtery(ibuf);
00262     imb_filterx(ibuf);
00263 }
00264 
00265 void IMB_mask_filter_extend(char *mask, int width, int height)
00266 {
00267     char *row1, *row2, *row3;
00268     int rowlen, x, y;
00269     char *temprect;
00270 
00271     rowlen= width;
00272 
00273     /* make a copy, to prevent flooding */
00274     temprect= MEM_dupallocN(mask);
00275 
00276     for(y=1; y<=height; y++) {
00277         /* setup rows */
00278         row1= (char *)(temprect + (y-2)*rowlen);
00279         row2= row1 + rowlen;
00280         row3= row2 + rowlen;
00281         if(y==1)
00282             row1= row2;
00283         else if(y==height)
00284             row3= row2;
00285 
00286         for(x=0; x<rowlen; x++) {
00287             if (mask[((y-1)*rowlen)+x]==0) {
00288                 if (*row1 || *row2 || *row3 || *(row1+1) || *(row3+1) ) {
00289                     mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
00290                 } else if((x!=rowlen-1) && (*(row1+2) || *(row2+2) || *(row3+2)) ) {
00291                     mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
00292                 }
00293             }
00294 
00295             if(x!=0) {
00296                 row1++; row2++; row3++;
00297             }
00298         }
00299     }
00300 
00301     MEM_freeN(temprect);
00302 }
00303 
00304 void IMB_mask_clear(ImBuf *ibuf, char *mask, int val)
00305 {
00306     int x,y;
00307     if (ibuf->rect_float) {
00308         for(x=0; x<ibuf->x; x++) {
00309             for(y=0; y<ibuf->y; y++) {
00310                 if (mask[ibuf->x*y + x] == val) {
00311                     float *col= ibuf->rect_float + 4*(ibuf->x*y + x);
00312                     col[0] = col[1] = col[2] = col[3] = 0.0f;
00313                 }
00314             }
00315         }
00316     } else {
00317         /* char buffer */
00318         for(x=0; x<ibuf->x; x++) {
00319             for(y=0; y<ibuf->y; y++) {
00320                 if (mask[ibuf->x*y + x] == val) {
00321                     char *col= (char *)(ibuf->rect + ibuf->x*y + x);
00322                     col[0] = col[1] = col[2] = col[3] = 0;
00323                 }
00324             }
00325         }
00326     }
00327 }
00328 
00329 static int filter_make_index(const int x, const int y, const int w, const int h)
00330 {
00331     if(x<0 || x>=w || y<0 || y>=h) return -1;   /* return bad index */
00332     else return y*w+x;
00333 }
00334 
00335 static int check_pixel_assigned(const void *buffer, const char *mask, const int index, const int depth, const int is_float)
00336 {
00337     int res = 0;
00338 
00339     if(index>=0) {
00340         const int alpha_index = depth*index+(depth-1);
00341 
00342         if(mask!=NULL) {
00343             res = mask[index]!=0 ? 1 : 0;
00344         }
00345         else if( (is_float && ((const float *) buffer)[alpha_index]!=0.0f) ||
00346                 (!is_float && ((const unsigned char *) buffer)[alpha_index]!=0) ) {
00347             res=1;
00348         }
00349     }
00350 
00351     return res;
00352 }
00353 
00354 /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
00355  * 
00356  * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
00357  * */
00358 void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
00359 {
00360     const int width= ibuf->x;
00361     const int height= ibuf->y;
00362     const int depth= 4;     /* always 4 channels */
00363     const int chsize= ibuf->rect_float ? sizeof(float) : sizeof(unsigned char);
00364     const int bsize= width*height*depth*chsize;
00365     const int is_float= ibuf->rect_float!=NULL;
00366     void *dstbuf= (void *) MEM_dupallocN(ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect);
00367     char *dstmask= mask==NULL ? NULL : (char *) MEM_dupallocN(mask);
00368     void *srcbuf= ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect;
00369     char *srcmask= mask;
00370     int cannot_early_out= 1, r, n, k, i, j, c;
00371     float weight[25];
00372 
00373     /* build a weights buffer */
00374     n= 1;
00375     /*k= 0;
00376     for(i = -n; i <= n; i++)
00377         for(j = -n; j <= n; j++)
00378             weight[k++] = sqrt((float) i * i + j * j);
00379             */
00380     weight[0]=1; weight[1]=2; weight[2]=1;
00381     weight[3]=2; weight[4]=0; weight[5]=2;
00382     weight[6]=1; weight[7]=2; weight[8]=1;
00383 
00384     /* run passes */
00385     for(r = 0; cannot_early_out == 1 && r < filter; r++) {
00386         int x, y;
00387         cannot_early_out = 0;
00388 
00389         for(y= 0; y<height; y++) {
00390             for(x= 0; x<width; x++) {
00391                 const int index= filter_make_index(x, y, width, height);
00392 
00393                 /* only update unassigned pixels */
00394                 if(!check_pixel_assigned(srcbuf, srcmask, index, depth, is_float)) {
00395                     float tmp[4];
00396                     float wsum=0;
00397                     float acc[4]={0,0,0,0};
00398                     k = 0;
00399 
00400                     if (check_pixel_assigned(srcbuf, srcmask, filter_make_index(x-1, y, width, height), depth, is_float) ||
00401                         check_pixel_assigned(srcbuf, srcmask, filter_make_index(x+1, y, width, height), depth, is_float) ||
00402                         check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y-1, width, height), depth, is_float) ||
00403                         check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y+1, width, height), depth, is_float)) {
00404                         for(i= -n; i<=n; i++) {
00405                             for(j=-n; j<=n; j++) {
00406                                 if(i != 0 || j != 0) {
00407                                     const int tmpindex= filter_make_index(x+i, y+j, width, height);
00408 
00409                                     if(check_pixel_assigned(srcbuf, srcmask, tmpindex, depth, is_float))    { 
00410                                         if(is_float) {
00411                                             for(c=0; c<depth; c++)
00412                                                 tmp[c] = ((const float *) srcbuf)[depth*tmpindex+c];
00413                                         }
00414                                         else {
00415                                             for(c=0; c<depth; c++)
00416                                                 tmp[c] = (float) ((const unsigned char *) srcbuf)[depth*tmpindex+c];
00417                                         }
00418 
00419                                         wsum+= weight[k];
00420 
00421                                         for(c=0; c<depth; c++)
00422                                             acc[c]+= weight[k] * tmp[c];
00423                                     }
00424                                 }
00425                                 k++;
00426                             }
00427                         }
00428 
00429                         if(wsum!=0) {
00430                             for(c=0; c<depth; c++)
00431                                 acc[c]/= wsum;
00432 
00433                             if(is_float) {
00434                                 for(c=0; c<depth; c++)
00435                                     ((float *) dstbuf)[depth*index+c] = acc[c];
00436                             }
00437                             else {
00438                                 for(c=0; c<depth; c++) {
00439                                     ((unsigned char *) dstbuf)[depth*index+c]= acc[c] > 255 ? 255 : (acc[c] < 0 ? 0 : ((unsigned char) (acc[c]+0.5f)));
00440                                 }
00441                             }
00442 
00443                             if(dstmask!=NULL) dstmask[index]=FILTER_MASK_MARGIN;    /* assigned */
00444                             cannot_early_out = 1;
00445                         }
00446                     }
00447                 }
00448             }
00449         }
00450 
00451         /* keep the original buffer up to date. */
00452         memcpy(srcbuf, dstbuf, bsize);
00453         if(dstmask!=NULL) memcpy(srcmask, dstmask, width*height);
00454     }
00455 
00456     /* free memory */
00457     MEM_freeN(dstbuf);
00458     if(dstmask!=NULL) MEM_freeN(dstmask);
00459 }
00460 
00461 /* threadsafe version, only recreates existing maps */
00462 void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
00463 {
00464     ImBuf *hbuf = ibuf;
00465     int curmap = 0;
00466     
00467     ibuf->miptot= 1;
00468     
00469     while(curmap < IB_MIPMAP_LEVELS) {
00470         
00471         if(ibuf->mipmap[curmap]) {
00472             
00473             if(use_filter) {
00474                 ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
00475                 IMB_filterN(nbuf, hbuf);
00476                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
00477                 IMB_freeImBuf(nbuf);
00478             }
00479             else
00480                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], hbuf);
00481         }
00482         
00483         ibuf->miptot= curmap+2;
00484         hbuf= ibuf->mipmap[curmap];
00485         if(hbuf)
00486             hbuf->miplevel= curmap+1;
00487         
00488         if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
00489             break;
00490         
00491         curmap++;
00492     }
00493 }
00494 
00495 /* frees too (if there) and recreates new data */
00496 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
00497 {
00498     ImBuf *hbuf = ibuf;
00499     int curmap = 0;
00500 
00501     imb_freemipmapImBuf(ibuf);
00502     
00503     ibuf->miptot= 1;
00504 
00505     while(curmap < IB_MIPMAP_LEVELS) {
00506         if(use_filter) {
00507             ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
00508             IMB_filterN(nbuf, hbuf);
00509             ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
00510             IMB_freeImBuf(nbuf);
00511         }
00512         else
00513             ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
00514 
00515         ibuf->miptot= curmap+2;
00516         hbuf= ibuf->mipmap[curmap];
00517         hbuf->miplevel= curmap+1;
00518 
00519         if(hbuf->x <= 2 && hbuf->y <= 2)
00520             break;
00521 
00522         curmap++;
00523     }
00524 }
00525 
00526 ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
00527 {
00528     CLAMP(level, 0, ibuf->miptot-1);
00529     return (level == 0)? ibuf: ibuf->mipmap[level-1];
00530 }
00531 
00532 void IMB_premultiply_rect(unsigned int *rect, char planes, int w, int h)
00533 {
00534     char *cp;
00535     int x, y, val;
00536 
00537     if(planes == 24) {  /* put alpha at 255 */
00538         cp= (char *)(rect);
00539 
00540         for(y=0; y<h; y++)
00541             for(x=0; x<w; x++, cp+=4)
00542                 cp[3]= 255;
00543     }
00544     else {
00545         cp= (char *)(rect);
00546 
00547         for(y=0; y<h; y++) {
00548             for(x=0; x<w; x++, cp+=4) {
00549                 val= cp[3];
00550                 cp[0]= (cp[0]*val)>>8;
00551                 cp[1]= (cp[1]*val)>>8;
00552                 cp[2]= (cp[2]*val)>>8;
00553             }
00554         }
00555     }
00556 }
00557 
00558 void IMB_premultiply_rect_float(float *rect_float, char planes, int w, int h)
00559 {
00560     float val, *cp;
00561     int x, y;
00562 
00563     if(planes==24) {    /* put alpha at 1.0 */
00564         cp= rect_float;
00565 
00566         for(y=0; y<h; y++)
00567             for(x=0; x<w; x++, cp+=4)
00568                 cp[3]= 1.0;
00569     }
00570     else {
00571         cp= rect_float;
00572         for(y=0; y<h; y++) {
00573             for(x=0; x<w; x++, cp+=4) {
00574                 val= cp[3];
00575                 cp[0]= cp[0]*val;
00576                 cp[1]= cp[1]*val;
00577                 cp[2]= cp[2]*val;
00578             }
00579         }
00580     }
00581 
00582 }
00583 
00584 void IMB_premultiply_alpha(ImBuf *ibuf)
00585 {
00586     if(ibuf==NULL)
00587         return;
00588 
00589     if(ibuf->rect)
00590         IMB_premultiply_rect(ibuf->rect, ibuf->planes, ibuf->x, ibuf->y);
00591 
00592     if(ibuf->rect_float)
00593         IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
00594 }
00595