Blender V2.61 - r43446
|
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