Blender  V2.59
filter.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): Morten Mikkelsen.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  * filter.c
00028  *
00029  * $Id: filter.c 38654 2011-07-24 10:26:22Z nazgul $
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->depth > 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->depth > 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->depth > 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->depth > 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= 2;
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         /* run passes */
00381         for(r = 0; cannot_early_out == 1 && r < filter; r++) {
00382                 int x, y;
00383                 cannot_early_out = 0;
00384 
00385                 for(y= 0; y<height; y++) {
00386                         for(x= 0; x<width; x++) {
00387                                 const int index= filter_make_index(x, y, width, height);
00388 
00389                                 /* only update unassigned pixels */
00390                                 if(!check_pixel_assigned(srcbuf, srcmask, index, depth, is_float)) {
00391                                         float tmp[4];
00392                                         float wsum=0;
00393                                         float acc[4]={0,0,0,0};
00394                                         k = 0;
00395 
00396                                         if (check_pixel_assigned(srcbuf, srcmask, filter_make_index(x-1, y, width, height), depth, is_float) ||
00397                                                 check_pixel_assigned(srcbuf, srcmask, filter_make_index(x+1, y, width, height), depth, is_float) ||
00398                                                 check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y-1, width, height), depth, is_float) ||
00399                                                 check_pixel_assigned(srcbuf, srcmask, filter_make_index(x, y+1, width, height), depth, is_float)) {
00400                                                 for(i= -n; i<=n; i++) {
00401                                                         for(j=-n; j<=n; j++) {
00402                                                                 if(i != 0 || j != 0) {
00403                                                                         const int tmpindex= filter_make_index(x+i, y+j, width, height);
00404 
00405                                                                         if(check_pixel_assigned(srcbuf, srcmask, tmpindex, depth, is_float))    { 
00406                                                                                 if(is_float) {
00407                                                                                         for(c=0; c<depth; c++)
00408                                                                                                 tmp[c] = ((const float *) srcbuf)[depth*tmpindex+c];
00409                                                                                 }
00410                                                                                 else {
00411                                                                                         for(c=0; c<depth; c++)
00412                                                                                                 tmp[c] = (float) ((const unsigned char *) srcbuf)[depth*tmpindex+c];
00413                                                                                 }
00414 
00415                                                                                 wsum+= weight[k];
00416 
00417                                                                                 for(c=0; c<depth; c++)
00418                                                                                         acc[c]+= weight[k] * tmp[c];
00419                                                                         }
00420                                                                 }
00421                                                                 k++;
00422                                                         }
00423                                                 }
00424 
00425                                                 if(wsum!=0) {
00426                                                         for(c=0; c<depth; c++)
00427                                                                 acc[c]/= wsum;
00428 
00429                                                         if(is_float) {
00430                                                                 for(c=0; c<depth; c++)
00431                                                                         ((float *) dstbuf)[depth*index+c] = acc[c];
00432                                                         }
00433                                                         else {
00434                                                                 for(c=0; c<depth; c++) {
00435                                                                         ((unsigned char *) dstbuf)[depth*index+c]= acc[c] > 255 ? 255 : (acc[c] < 0 ? 0 : ((unsigned char) (acc[c]+0.5f)));
00436                                                                 }
00437                                                         }
00438 
00439                                                         if(dstmask!=NULL) dstmask[index]=FILTER_MASK_MARGIN;    /* assigned */
00440                                                         cannot_early_out = 1;
00441                                                 }
00442                                         }
00443                                 }
00444                         }
00445                 }
00446 
00447                 /* keep the original buffer up to date. */
00448                 memcpy(srcbuf, dstbuf, bsize);
00449                 if(dstmask!=NULL) memcpy(srcmask, dstmask, width*height);
00450         }
00451 
00452         /* free memory */
00453         MEM_freeN(dstbuf);
00454         if(dstmask!=NULL) MEM_freeN(dstmask);
00455 }
00456 
00457 /* threadsafe version, only recreates existing maps */
00458 void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
00459 {
00460         ImBuf *hbuf = ibuf;
00461         int curmap = 0;
00462         
00463         ibuf->miptot= 1;
00464         
00465         while(curmap < IB_MIPMAP_LEVELS) {
00466                 
00467                 if(ibuf->mipmap[curmap]) {
00468                         
00469                         if(use_filter) {
00470                                 ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
00471                                 IMB_filterN(nbuf, hbuf);
00472                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
00473                                 IMB_freeImBuf(nbuf);
00474                         }
00475                         else
00476                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], hbuf);
00477                 }
00478                 
00479                 ibuf->miptot= curmap+2;
00480                 hbuf= ibuf->mipmap[curmap];
00481                 if(hbuf)
00482                         hbuf->miplevel= curmap+1;
00483                 
00484                 if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
00485                         break;
00486                 
00487                 curmap++;
00488         }
00489 }
00490 
00491 /* frees too (if there) and recreates new data */
00492 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
00493 {
00494         ImBuf *hbuf = ibuf;
00495         int curmap = 0;
00496 
00497         imb_freemipmapImBuf(ibuf);
00498         
00499         ibuf->miptot= 1;
00500 
00501         while(curmap < IB_MIPMAP_LEVELS) {
00502                 if(use_filter) {
00503                         ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
00504                         IMB_filterN(nbuf, hbuf);
00505                         ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
00506                         IMB_freeImBuf(nbuf);
00507                 }
00508                 else
00509                         ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
00510 
00511                 ibuf->miptot= curmap+2;
00512                 hbuf= ibuf->mipmap[curmap];
00513                 hbuf->miplevel= curmap+1;
00514 
00515                 if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
00516                         break;
00517 
00518                 curmap++;
00519         }
00520 }
00521 
00522 ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
00523 {
00524         CLAMP(level, 0, ibuf->miptot-1);
00525         return (level == 0)? ibuf: ibuf->mipmap[level-1];
00526 }
00527 
00528 void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
00529 {
00530         char *cp;
00531         int x, y, val;
00532 
00533         if(depth == 24) {       /* put alpha at 255 */
00534                 cp= (char *)(rect);
00535 
00536                 for(y=0; y<h; y++)
00537                         for(x=0; x<w; x++, cp+=4)
00538                                 cp[3]= 255;
00539         }
00540         else {
00541                 cp= (char *)(rect);
00542 
00543                 for(y=0; y<h; y++) {
00544                         for(x=0; x<w; x++, cp+=4) {
00545                                 val= cp[3];
00546                                 cp[0]= (cp[0]*val)>>8;
00547                                 cp[1]= (cp[1]*val)>>8;
00548                                 cp[2]= (cp[2]*val)>>8;
00549                         }
00550                 }
00551         }
00552 }
00553 
00554 void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
00555 {
00556         float val, *cp;
00557         int x, y;
00558 
00559         if(depth==24) { /* put alpha at 1.0 */
00560                 cp= rect_float;
00561 
00562                 for(y=0; y<h; y++)
00563                         for(x=0; x<w; x++, cp+=4)
00564                                 cp[3]= 1.0;
00565         }
00566         else {
00567                 cp= rect_float;
00568                 for(y=0; y<h; y++) {
00569                         for(x=0; x<w; x++, cp+=4) {
00570                                 val= cp[3];
00571                                 cp[0]= cp[0]*val;
00572                                 cp[1]= cp[1]*val;
00573                                 cp[2]= cp[2]*val;
00574                         }
00575                 }
00576         }
00577 
00578 }
00579 
00580 void IMB_premultiply_alpha(ImBuf *ibuf)
00581 {
00582         if(ibuf==NULL)
00583                 return;
00584 
00585         if(ibuf->rect)
00586                 IMB_premultiply_rect(ibuf->rect, ibuf->depth, ibuf->x, ibuf->y);
00587 
00588         if(ibuf->rect_float)
00589                 IMB_premultiply_rect_float(ibuf->rect_float, ibuf->depth, ibuf->x, ibuf->y);
00590 }
00591