|
Blender
V2.59
|
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