Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2005 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL/BL DUAL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <string.h> 00034 #include <math.h> 00035 #include <stdlib.h> 00036 #include <float.h> 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "DNA_color_types.h" 00041 #include "DNA_curve_types.h" 00042 00043 #include "BLI_blenlib.h" 00044 #include "BLI_math.h" 00045 #include "BLI_utildefines.h" 00046 00047 #include "BKE_colortools.h" 00048 #include "BKE_curve.h" 00049 #include "BKE_fcurve.h" 00050 00051 00052 #include "IMB_imbuf.h" 00053 #include "IMB_imbuf_types.h" 00054 00055 /* ********************************* color curve ********************* */ 00056 00057 /* ***************** operations on full struct ************* */ 00058 00059 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy) 00060 { 00061 CurveMapping *cumap; 00062 int a; 00063 float clipminx, clipminy, clipmaxx, clipmaxy; 00064 00065 cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap"); 00066 cumap->flag= CUMA_DO_CLIP; 00067 if(tot==4) cumap->cur= 3; /* rhms, hack for 'col' curve? */ 00068 00069 clipminx = MIN2(minx, maxx); 00070 clipminy = MIN2(miny, maxy); 00071 clipmaxx = MAX2(minx, maxx); 00072 clipmaxy = MAX2(miny, maxy); 00073 00074 BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy); 00075 cumap->clipr= cumap->curr; 00076 00077 cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f; 00078 cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f; 00079 00080 for(a=0; a<tot; a++) { 00081 cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE; 00082 cumap->cm[a].totpoint= 2; 00083 cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points"); 00084 00085 cumap->cm[a].curve[0].x= minx; 00086 cumap->cm[a].curve[0].y= miny; 00087 cumap->cm[a].curve[1].x= maxx; 00088 cumap->cm[a].curve[1].y= maxy; 00089 } 00090 00091 cumap->changed_timestamp = 0; 00092 00093 return cumap; 00094 } 00095 00096 void curvemapping_free(CurveMapping *cumap) 00097 { 00098 int a; 00099 00100 if(cumap) { 00101 for(a=0; a<CM_TOT; a++) { 00102 if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve); 00103 if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table); 00104 if(cumap->cm[a].premultable) MEM_freeN(cumap->cm[a].premultable); 00105 } 00106 MEM_freeN(cumap); 00107 } 00108 } 00109 00110 CurveMapping *curvemapping_copy(CurveMapping *cumap) 00111 { 00112 int a; 00113 00114 if(cumap) { 00115 CurveMapping *cumapn= MEM_dupallocN(cumap); 00116 for(a=0; a<CM_TOT; a++) { 00117 if(cumap->cm[a].curve) 00118 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve); 00119 if(cumap->cm[a].table) 00120 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table); 00121 if(cumap->cm[a].premultable) 00122 cumapn->cm[a].premultable= MEM_dupallocN(cumap->cm[a].premultable); 00123 } 00124 return cumapn; 00125 } 00126 return NULL; 00127 } 00128 00129 void curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3]) 00130 { 00131 int a; 00132 00133 if(white) 00134 copy_v3_v3(cumap->white, white); 00135 if(black) 00136 copy_v3_v3(cumap->black, black); 00137 00138 for(a=0; a<3; a++) { 00139 if(cumap->white[a]==cumap->black[a]) 00140 cumap->bwmul[a]= 0.0f; 00141 else 00142 cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]); 00143 } 00144 } 00145 00146 /* ***************** operations on single curve ************* */ 00147 /* ********** NOTE: requires curvemapping_changed() call after ******** */ 00148 00149 /* removes with flag set */ 00150 void curvemap_remove(CurveMap *cuma, int flag) 00151 { 00152 CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points"); 00153 int a, b, removed=0; 00154 00155 /* well, lets keep the two outer points! */ 00156 cmp[0]= cuma->curve[0]; 00157 for(a=1, b=1; a<cuma->totpoint-1; a++) { 00158 if(!(cuma->curve[a].flag & flag)) { 00159 cmp[b]= cuma->curve[a]; 00160 b++; 00161 } 00162 else removed++; 00163 } 00164 cmp[b]= cuma->curve[a]; 00165 00166 MEM_freeN(cuma->curve); 00167 cuma->curve= cmp; 00168 cuma->totpoint -= removed; 00169 } 00170 00171 void curvemap_insert(CurveMap *cuma, float x, float y) 00172 { 00173 CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points"); 00174 int a, b, foundloc= 0; 00175 00176 /* insert fragments of the old one and the new point to the new curve */ 00177 cuma->totpoint++; 00178 for(a=0, b=0; a<cuma->totpoint; a++) { 00179 if((x < cuma->curve[a].x) && !foundloc) { 00180 cmp[a].x= x; 00181 cmp[a].y= y; 00182 cmp[a].flag= CUMA_SELECT; 00183 foundloc= 1; 00184 } 00185 else { 00186 cmp[a].x= cuma->curve[b].x; 00187 cmp[a].y= cuma->curve[b].y; 00188 cmp[a].flag= cuma->curve[b].flag; 00189 cmp[a].flag &= ~CUMA_SELECT; /* make sure old points don't remain selected */ 00190 cmp[a].shorty= cuma->curve[b].shorty; 00191 b++; 00192 } 00193 } 00194 00195 /* free old curve and replace it with new one */ 00196 MEM_freeN(cuma->curve); 00197 cuma->curve= cmp; 00198 } 00199 00200 void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset, int slope) 00201 { 00202 if(cuma->curve) 00203 MEM_freeN(cuma->curve); 00204 00205 switch(preset) { 00206 case CURVE_PRESET_LINE: cuma->totpoint= 2; break; 00207 case CURVE_PRESET_SHARP: cuma->totpoint= 4; break; 00208 case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break; 00209 case CURVE_PRESET_MAX: cuma->totpoint= 2; break; 00210 case CURVE_PRESET_MID9: cuma->totpoint= 9; break; 00211 case CURVE_PRESET_ROUND: cuma->totpoint= 4; break; 00212 case CURVE_PRESET_ROOT: cuma->totpoint= 4; break; 00213 } 00214 00215 cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points"); 00216 00217 switch(preset) { 00218 case CURVE_PRESET_LINE: 00219 cuma->curve[0].x= clipr->xmin; 00220 cuma->curve[0].y= clipr->ymax; 00221 cuma->curve[0].flag= 0; 00222 cuma->curve[1].x= clipr->xmax; 00223 cuma->curve[1].y= clipr->ymin; 00224 cuma->curve[1].flag= 0; 00225 break; 00226 case CURVE_PRESET_SHARP: 00227 cuma->curve[0].x= 0; 00228 cuma->curve[0].y= 1; 00229 cuma->curve[1].x= 0.25; 00230 cuma->curve[1].y= 0.50; 00231 cuma->curve[2].x= 0.75; 00232 cuma->curve[2].y= 0.04; 00233 cuma->curve[3].x= 1; 00234 cuma->curve[3].y= 0; 00235 break; 00236 case CURVE_PRESET_SMOOTH: 00237 cuma->curve[0].x= 0; 00238 cuma->curve[0].y= 1; 00239 cuma->curve[1].x= 0.25; 00240 cuma->curve[1].y= 0.94; 00241 cuma->curve[2].x= 0.75; 00242 cuma->curve[2].y= 0.06; 00243 cuma->curve[3].x= 1; 00244 cuma->curve[3].y= 0; 00245 break; 00246 case CURVE_PRESET_MAX: 00247 cuma->curve[0].x= 0; 00248 cuma->curve[0].y= 1; 00249 cuma->curve[1].x= 1; 00250 cuma->curve[1].y= 1; 00251 break; 00252 case CURVE_PRESET_MID9: 00253 { 00254 int i; 00255 for (i=0; i < cuma->totpoint; i++) 00256 { 00257 cuma->curve[i].x= i / ((float)cuma->totpoint-1); 00258 cuma->curve[i].y= 0.5; 00259 } 00260 } 00261 break; 00262 case CURVE_PRESET_ROUND: 00263 cuma->curve[0].x= 0; 00264 cuma->curve[0].y= 1; 00265 cuma->curve[1].x= 0.5; 00266 cuma->curve[1].y= 0.90; 00267 cuma->curve[2].x= 0.86; 00268 cuma->curve[2].y= 0.5; 00269 cuma->curve[3].x= 1; 00270 cuma->curve[3].y= 0; 00271 break; 00272 case CURVE_PRESET_ROOT: 00273 cuma->curve[0].x= 0; 00274 cuma->curve[0].y= 1; 00275 cuma->curve[1].x= 0.25; 00276 cuma->curve[1].y= 0.95; 00277 cuma->curve[2].x= 0.75; 00278 cuma->curve[2].y= 0.44; 00279 cuma->curve[3].x= 1; 00280 cuma->curve[3].y= 0; 00281 break; 00282 } 00283 00284 /* mirror curve in x direction to have positive slope 00285 * rather than default negative slope */ 00286 if (slope == CURVEMAP_SLOPE_POSITIVE) { 00287 int i, last=cuma->totpoint-1; 00288 CurveMapPoint *newpoints= MEM_dupallocN(cuma->curve); 00289 00290 for (i=0; i<cuma->totpoint; i++) { 00291 newpoints[i].y = cuma->curve[last-i].y; 00292 } 00293 00294 MEM_freeN(cuma->curve); 00295 cuma->curve = newpoints; 00296 } 00297 00298 if(cuma->table) { 00299 MEM_freeN(cuma->table); 00300 cuma->table= NULL; 00301 } 00302 } 00303 00304 /* if type==1: vector, else auto */ 00305 void curvemap_sethandle(CurveMap *cuma, int type) 00306 { 00307 int a; 00308 00309 for(a=0; a<cuma->totpoint; a++) { 00310 if(cuma->curve[a].flag & CUMA_SELECT) { 00311 if(type) cuma->curve[a].flag |= CUMA_VECTOR; 00312 else cuma->curve[a].flag &= ~CUMA_VECTOR; 00313 } 00314 } 00315 } 00316 00317 /* *********************** Making the tables and display ************** */ 00318 00319 /* reduced copy of garbled calchandleNurb() code in curve.c */ 00320 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode)) 00321 { 00322 float *p1,*p2,*p3,pt[3]; 00323 float len,len_a, len_b; 00324 float dvec_a[2], dvec_b[2]; 00325 00326 if(bezt->h1==0 && bezt->h2==0) { 00327 return; 00328 } 00329 00330 p2= bezt->vec[1]; 00331 00332 if(prev==NULL) { 00333 p3= next->vec[1]; 00334 pt[0]= 2.0f*p2[0] - p3[0]; 00335 pt[1]= 2.0f*p2[1] - p3[1]; 00336 p1= pt; 00337 } 00338 else { 00339 p1= prev->vec[1]; 00340 } 00341 00342 if(next==NULL) { 00343 p1= prev->vec[1]; 00344 pt[0]= 2.0f*p2[0] - p1[0]; 00345 pt[1]= 2.0f*p2[1] - p1[1]; 00346 p3= pt; 00347 } 00348 else { 00349 p3= next->vec[1]; 00350 } 00351 00352 sub_v2_v2v2(dvec_a, p2, p1); 00353 sub_v2_v2v2(dvec_b, p3, p2); 00354 00355 len_a= len_v2(dvec_a); 00356 len_b= len_v2(dvec_b); 00357 00358 if(len_a==0.0f) len_a=1.0f; 00359 if(len_b==0.0f) len_b=1.0f; 00360 00361 if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ 00362 float tvec[2]; 00363 tvec[0]= dvec_b[0]/len_b + dvec_a[0]/len_a; 00364 tvec[1]= dvec_b[1]/len_b + dvec_a[1]/len_a; 00365 00366 len= len_v2(tvec) * 2.5614f; 00367 if(len!=0.0f) { 00368 00369 if(bezt->h1==HD_AUTO) { 00370 len_a/=len; 00371 madd_v2_v2v2fl(p2-3, p2, tvec, -len_a); 00372 } 00373 if(bezt->h2==HD_AUTO) { 00374 len_b/=len; 00375 madd_v2_v2v2fl(p2+3, p2, tvec, len_b); 00376 } 00377 } 00378 } 00379 00380 if(bezt->h1==HD_VECT) { /* vector */ 00381 madd_v2_v2v2fl(p2-3, p2, dvec_a, -1.0f/3.0f); 00382 } 00383 if(bezt->h2==HD_VECT) { 00384 madd_v2_v2v2fl(p2+3, p2, dvec_b, 1.0f/3.0f); 00385 } 00386 } 00387 00388 /* in X, out Y. 00389 X is presumed to be outside first or last */ 00390 static float curvemap_calc_extend(CurveMap *cuma, float x, const float first[2], const float last[2]) 00391 { 00392 if(x <= first[0]) { 00393 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { 00394 /* no extrapolate */ 00395 return first[1]; 00396 } 00397 else { 00398 if(cuma->ext_in[0]==0.0f) 00399 return first[1] + cuma->ext_in[1]*10000.0f; 00400 else 00401 return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0]; 00402 } 00403 } 00404 else if(x >= last[0]) { 00405 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { 00406 /* no extrapolate */ 00407 return last[1]; 00408 } 00409 else { 00410 if(cuma->ext_out[0]==0.0f) 00411 return last[1] - cuma->ext_out[1]*10000.0f; 00412 else 00413 return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0]; 00414 } 00415 } 00416 return 0.0f; 00417 } 00418 00419 /* only creates a table for a single channel in CurveMapping */ 00420 static void curvemap_make_table(CurveMap *cuma, rctf *clipr) 00421 { 00422 CurveMapPoint *cmp= cuma->curve; 00423 BezTriple *bezt; 00424 float *fp, *allpoints, *lastpoint, curf, range; 00425 int a, totpoint; 00426 00427 if(cuma->curve==NULL) return; 00428 00429 /* default rect also is table range */ 00430 cuma->mintable= clipr->xmin; 00431 cuma->maxtable= clipr->xmax; 00432 00433 /* hrmf... we now rely on blender ipo beziers, these are more advanced */ 00434 bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr"); 00435 00436 for(a=0; a<cuma->totpoint; a++) { 00437 cuma->mintable= MIN2(cuma->mintable, cmp[a].x); 00438 cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x); 00439 bezt[a].vec[1][0]= cmp[a].x; 00440 bezt[a].vec[1][1]= cmp[a].y; 00441 if(cmp[a].flag & CUMA_VECTOR) 00442 bezt[a].h1= bezt[a].h2= HD_VECT; 00443 else 00444 bezt[a].h1= bezt[a].h2= HD_AUTO; 00445 } 00446 00447 for(a=0; a<cuma->totpoint; a++) { 00448 if(a==0) 00449 calchandle_curvemap(bezt, NULL, bezt+1, 0); 00450 else if(a==cuma->totpoint-1) 00451 calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0); 00452 else 00453 calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0); 00454 } 00455 00456 /* first and last handle need correction, instead of pointing to center of next/prev, 00457 we let it point to the closest handle */ 00458 if(cuma->totpoint>2) { 00459 float hlen, nlen, vec[3]; 00460 00461 if(bezt[0].h2==HD_AUTO) { 00462 00463 hlen= len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */ 00464 /* clip handle point */ 00465 copy_v3_v3(vec, bezt[1].vec[0]); 00466 if(vec[0] < bezt[0].vec[1][0]) 00467 vec[0]= bezt[0].vec[1][0]; 00468 00469 sub_v3_v3(vec, bezt[0].vec[1]); 00470 nlen= len_v3(vec); 00471 if(nlen>FLT_EPSILON) { 00472 mul_v3_fl(vec, hlen/nlen); 00473 add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]); 00474 sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec); 00475 } 00476 } 00477 a= cuma->totpoint-1; 00478 if(bezt[a].h2==HD_AUTO) { 00479 00480 hlen= len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ 00481 /* clip handle point */ 00482 copy_v3_v3(vec, bezt[a-1].vec[2]); 00483 if(vec[0] > bezt[a].vec[1][0]) 00484 vec[0]= bezt[a].vec[1][0]; 00485 00486 sub_v3_v3(vec, bezt[a].vec[1]); 00487 nlen= len_v3(vec); 00488 if(nlen>FLT_EPSILON) { 00489 mul_v3_fl(vec, hlen/nlen); 00490 add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]); 00491 sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec); 00492 } 00493 } 00494 } 00495 /* make the bezier curve */ 00496 if(cuma->table) 00497 MEM_freeN(cuma->table); 00498 totpoint= (cuma->totpoint-1)*CM_RESOL; 00499 fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table"); 00500 00501 for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) { 00502 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]); 00503 forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2*sizeof(float)); 00504 forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2*sizeof(float)); 00505 } 00506 00507 /* store first and last handle for extrapolation, unit length */ 00508 cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0]; 00509 cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1]; 00510 range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]); 00511 cuma->ext_in[0]/= range; 00512 cuma->ext_in[1]/= range; 00513 00514 a= cuma->totpoint-1; 00515 cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0]; 00516 cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1]; 00517 range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]); 00518 cuma->ext_out[0]/= range; 00519 cuma->ext_out[1]/= range; 00520 00521 /* cleanup */ 00522 MEM_freeN(bezt); 00523 00524 range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable); 00525 cuma->range= 1.0f/range; 00526 00527 /* now make a table with CM_TABLE equal x distances */ 00528 fp= allpoints; 00529 lastpoint= allpoints + 2*(totpoint-1); 00530 cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table"); 00531 00532 for(a=0; a<=CM_TABLE; a++) { 00533 curf= cuma->mintable + range*(float)a; 00534 cmp[a].x= curf; 00535 00536 /* get the first x coordinate larger than curf */ 00537 while(curf >= fp[0] && fp!=lastpoint) { 00538 fp+=2; 00539 } 00540 if(fp==allpoints || (curf >= fp[0] && fp==lastpoint)) 00541 cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint); 00542 else { 00543 float fac1= fp[0] - fp[-2]; 00544 float fac2= fp[0] - curf; 00545 if(fac1 > FLT_EPSILON) 00546 fac1= fac2/fac1; 00547 else 00548 fac1= 0.0f; 00549 cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1]; 00550 } 00551 } 00552 00553 MEM_freeN(allpoints); 00554 cuma->table= cmp; 00555 } 00556 00557 /* call when you do images etc, needs restore too. also verifies tables */ 00558 /* it uses a flag to prevent premul or free to happen twice */ 00559 void curvemapping_premultiply(CurveMapping *cumap, int restore) 00560 { 00561 int a; 00562 00563 if(restore) { 00564 if(cumap->flag & CUMA_PREMULLED) { 00565 for(a=0; a<3; a++) { 00566 MEM_freeN(cumap->cm[a].table); 00567 cumap->cm[a].table= cumap->cm[a].premultable; 00568 cumap->cm[a].premultable= NULL; 00569 } 00570 00571 cumap->flag &= ~CUMA_PREMULLED; 00572 } 00573 } 00574 else { 00575 if((cumap->flag & CUMA_PREMULLED)==0) { 00576 /* verify and copy */ 00577 for(a=0; a<3; a++) { 00578 if(cumap->cm[a].table==NULL) 00579 curvemap_make_table(cumap->cm+a, &cumap->clipr); 00580 cumap->cm[a].premultable= cumap->cm[a].table; 00581 cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table"); 00582 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint)); 00583 } 00584 00585 if(cumap->cm[3].table==NULL) 00586 curvemap_make_table(cumap->cm+3, &cumap->clipr); 00587 00588 /* premul */ 00589 for(a=0; a<3; a++) { 00590 int b; 00591 for(b=0; b<=CM_TABLE; b++) { 00592 cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y); 00593 } 00594 } 00595 00596 cumap->flag |= CUMA_PREMULLED; 00597 } 00598 } 00599 } 00600 00601 static int sort_curvepoints(const void *a1, const void *a2) 00602 { 00603 const struct CurveMapPoint *x1=a1, *x2=a2; 00604 00605 if( x1->x > x2->x ) return 1; 00606 else if( x1->x < x2->x) return -1; 00607 return 0; 00608 } 00609 00610 /* ************************ more CurveMapping calls *************** */ 00611 00612 /* note; only does current curvemap! */ 00613 void curvemapping_changed(CurveMapping *cumap, int rem_doubles) 00614 { 00615 CurveMap *cuma= cumap->cm+cumap->cur; 00616 CurveMapPoint *cmp= cuma->curve; 00617 rctf *clipr= &cumap->clipr; 00618 float thresh= 0.01f*(clipr->xmax - clipr->xmin); 00619 float dx= 0.0f, dy= 0.0f; 00620 int a; 00621 00622 cumap->changed_timestamp++; 00623 00624 /* clamp with clip */ 00625 if(cumap->flag & CUMA_DO_CLIP) { 00626 for(a=0; a<cuma->totpoint; a++) { 00627 if(cmp[a].flag & CUMA_SELECT) { 00628 if(cmp[a].x < clipr->xmin) 00629 dx= MIN2(dx, cmp[a].x - clipr->xmin); 00630 else if(cmp[a].x > clipr->xmax) 00631 dx= MAX2(dx, cmp[a].x - clipr->xmax); 00632 if(cmp[a].y < clipr->ymin) 00633 dy= MIN2(dy, cmp[a].y - clipr->ymin); 00634 else if(cmp[a].y > clipr->ymax) 00635 dy= MAX2(dy, cmp[a].y - clipr->ymax); 00636 } 00637 } 00638 for(a=0; a<cuma->totpoint; a++) { 00639 if(cmp[a].flag & CUMA_SELECT) { 00640 cmp[a].x -= dx; 00641 cmp[a].y -= dy; 00642 } 00643 } 00644 } 00645 00646 00647 qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints); 00648 00649 /* remove doubles, threshold set on 1% of default range */ 00650 if(rem_doubles && cuma->totpoint>2) { 00651 for(a=0; a<cuma->totpoint-1; a++) { 00652 dx= cmp[a].x - cmp[a+1].x; 00653 dy= cmp[a].y - cmp[a+1].y; 00654 if( sqrtf(dx*dx + dy*dy) < thresh ) { 00655 if(a==0) { 00656 cmp[a+1].flag|= 2; 00657 if(cmp[a+1].flag & CUMA_SELECT) 00658 cmp[a].flag |= CUMA_SELECT; 00659 } 00660 else { 00661 cmp[a].flag|= 2; 00662 if(cmp[a].flag & CUMA_SELECT) 00663 cmp[a+1].flag |= CUMA_SELECT; 00664 } 00665 break; /* we assume 1 deletion per edit is ok */ 00666 } 00667 } 00668 if(a != cuma->totpoint-1) 00669 curvemap_remove(cuma, 2); 00670 } 00671 curvemap_make_table(cuma, clipr); 00672 } 00673 00674 /* table should be verified */ 00675 float curvemap_evaluateF(CurveMap *cuma, float value) 00676 { 00677 float fi; 00678 int i; 00679 00680 /* index in table */ 00681 fi= (value-cuma->mintable)*cuma->range; 00682 i= (int)fi; 00683 00684 /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */ 00685 if(fi<0.0f || fi>CM_TABLE) 00686 return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x); 00687 else { 00688 if(i<0) return cuma->table[0].y; 00689 if(i>=CM_TABLE) return cuma->table[CM_TABLE].y; 00690 00691 fi= fi-(float)i; 00692 return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; 00693 } 00694 } 00695 00696 /* works with curve 'cur' */ 00697 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value) 00698 { 00699 CurveMap *cuma= cumap->cm+cur; 00700 00701 /* allocate or bail out */ 00702 if(cuma->table==NULL) { 00703 curvemap_make_table(cuma, &cumap->clipr); 00704 if(cuma->table==NULL) 00705 return 1.0f-value; 00706 } 00707 return curvemap_evaluateF(cuma, value); 00708 } 00709 00710 /* vector case */ 00711 void curvemapping_evaluate3F(CurveMapping *cumap, float vecout[3], const float vecin[3]) 00712 { 00713 vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]); 00714 vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]); 00715 vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]); 00716 } 00717 00718 /* RGB case, no black/white points, no premult */ 00719 void curvemapping_evaluateRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3]) 00720 { 00721 vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0])); 00722 vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1])); 00723 vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2])); 00724 } 00725 00726 00727 /* RGB with black/white points and premult. tables are checked */ 00728 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3]) 00729 { 00730 float fac; 00731 00732 fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0]; 00733 vecout[0]= curvemap_evaluateF(cumap->cm, fac); 00734 00735 fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1]; 00736 vecout[1]= curvemap_evaluateF(cumap->cm+1, fac); 00737 00738 fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2]; 00739 vecout[2]= curvemap_evaluateF(cumap->cm+2, fac); 00740 } 00741 00742 00743 /* only used for image editor curves */ 00744 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf) 00745 { 00746 ImBuf *tmpbuf; 00747 int pixel; 00748 float *pix_in; 00749 float col[3]; 00750 int stride= 4; 00751 float *pix_out; 00752 00753 if(ibuf==NULL) 00754 return; 00755 if(ibuf->rect_float==NULL) 00756 IMB_float_from_rect(ibuf); 00757 else if(ibuf->rect==NULL) 00758 imb_addrectImBuf(ibuf); 00759 00760 if (!ibuf->rect || !ibuf->rect_float) 00761 return; 00762 00763 /* work on a temp buffer, so can color manage afterwards. 00764 * No worse off memory wise than comp nodes */ 00765 tmpbuf = IMB_dupImBuf(ibuf); 00766 00767 curvemapping_premultiply(cumap, 0); 00768 00769 pix_in= ibuf->rect_float; 00770 pix_out= tmpbuf->rect_float; 00771 00772 if(ibuf->channels) 00773 stride= ibuf->channels; 00774 00775 for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pix_in+=stride, pix_out+=stride) { 00776 if(stride<3) { 00777 col[0]= curvemap_evaluateF(cumap->cm, *pix_in); 00778 00779 pix_out[1]= pix_out[2]= pix_out[3]= pix_out[0]= col[0]; 00780 } 00781 else { 00782 curvemapping_evaluate_premulRGBF(cumap, col, pix_in); 00783 pix_out[0]= col[0]; 00784 pix_out[1]= col[1]; 00785 pix_out[2]= col[2]; 00786 if(stride>3) 00787 pix_out[3]= pix_in[3]; 00788 else 00789 pix_out[3]= 1.f; 00790 } 00791 } 00792 00793 IMB_rect_from_float(tmpbuf); 00794 SWAP(unsigned int *, tmpbuf->rect, ibuf->rect); 00795 IMB_freeImBuf(tmpbuf); 00796 00797 curvemapping_premultiply(cumap, 1); 00798 } 00799 00800 int curvemapping_RGBA_does_something(CurveMapping *cumap) 00801 { 00802 int a; 00803 00804 if(cumap->black[0]!=0.0f) return 1; 00805 if(cumap->black[1]!=0.0f) return 1; 00806 if(cumap->black[2]!=0.0f) return 1; 00807 if(cumap->white[0]!=1.0f) return 1; 00808 if(cumap->white[1]!=1.0f) return 1; 00809 if(cumap->white[2]!=1.0f) return 1; 00810 00811 for(a=0; a<CM_TOT; a++) { 00812 if(cumap->cm[a].curve) { 00813 if(cumap->cm[a].totpoint!=2) return 1; 00814 00815 if(cumap->cm[a].curve[0].x != 0.0f) return 1; 00816 if(cumap->cm[a].curve[0].y != 0.0f) return 1; 00817 if(cumap->cm[a].curve[1].x != 1.0f) return 1; 00818 if(cumap->cm[a].curve[1].y != 1.0f) return 1; 00819 } 00820 } 00821 return 0; 00822 } 00823 00824 void curvemapping_initialize(CurveMapping *cumap) 00825 { 00826 int a; 00827 00828 if(cumap==NULL) return; 00829 00830 for(a=0; a<CM_TOT; a++) { 00831 if(cumap->cm[a].table==NULL) 00832 curvemap_make_table(cumap->cm+a, &cumap->clipr); 00833 } 00834 } 00835 00836 void curvemapping_table_RGBA(CurveMapping *cumap, float **array, int *size) 00837 { 00838 int a; 00839 00840 *size = CM_TABLE+1; 00841 *array = MEM_callocN(sizeof(float)*(*size)*4, "CurveMapping"); 00842 curvemapping_initialize(cumap); 00843 00844 for(a=0; a<*size; a++) { 00845 if(cumap->cm[0].table) 00846 (*array)[a*4+0]= cumap->cm[0].table[a].y; 00847 if(cumap->cm[1].table) 00848 (*array)[a*4+1]= cumap->cm[1].table[a].y; 00849 if(cumap->cm[2].table) 00850 (*array)[a*4+2]= cumap->cm[2].table[a].y; 00851 if(cumap->cm[3].table) 00852 (*array)[a*4+3]= cumap->cm[3].table[a].y; 00853 } 00854 } 00855 00856 /* ***************** Histogram **************** */ 00857 00858 #define INV_255 (1.f/255.f) 00859 00860 DO_INLINE int get_bin_float(float f) 00861 { 00862 int bin= (int)((f*255.0f) + 0.5f); /* 0.5 to prevent quantisation differences */ 00863 00864 /* note: clamp integer instead of float to avoid problems with NaN */ 00865 CLAMP(bin, 0, 255); 00866 00867 return bin; 00868 } 00869 00870 DO_INLINE void save_sample_line(Scopes *scopes, const int idx, const float fx, float *rgb, float *ycc) 00871 { 00872 float yuv[3]; 00873 00874 /* vectorscope*/ 00875 rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2]); 00876 scopes->vecscope[idx + 0] = yuv[1]; 00877 scopes->vecscope[idx + 1] = yuv[2]; 00878 00879 /* waveform */ 00880 switch (scopes->wavefrm_mode) { 00881 case SCOPES_WAVEFRM_RGB: 00882 scopes->waveform_1[idx + 0] = fx; 00883 scopes->waveform_1[idx + 1] = rgb[0]; 00884 scopes->waveform_2[idx + 0] = fx; 00885 scopes->waveform_2[idx + 1] = rgb[1]; 00886 scopes->waveform_3[idx + 0] = fx; 00887 scopes->waveform_3[idx + 1] = rgb[2]; 00888 break; 00889 case SCOPES_WAVEFRM_LUMA: 00890 scopes->waveform_1[idx + 0] = fx; 00891 scopes->waveform_1[idx + 1] = ycc[0]; 00892 break; 00893 case SCOPES_WAVEFRM_YCC_JPEG: 00894 case SCOPES_WAVEFRM_YCC_709: 00895 case SCOPES_WAVEFRM_YCC_601: 00896 scopes->waveform_1[idx + 0] = fx; 00897 scopes->waveform_1[idx + 1] = ycc[0]; 00898 scopes->waveform_2[idx + 0] = fx; 00899 scopes->waveform_2[idx + 1] = ycc[1]; 00900 scopes->waveform_3[idx + 0] = fx; 00901 scopes->waveform_3[idx + 1] = ycc[2]; 00902 break; 00903 } 00904 } 00905 00906 void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) 00907 { 00908 int x, y, c; 00909 unsigned int n, nl; 00910 double div, divl; 00911 float *rf=NULL; 00912 unsigned char *rc=NULL; 00913 unsigned int *bin_r, *bin_g, *bin_b, *bin_lum; 00914 int savedlines, saveline; 00915 float rgb[3], ycc[3], luma; 00916 int ycc_mode=-1; 00917 const short is_float = (ibuf->rect_float != NULL); 00918 00919 if (ibuf->rect==NULL && ibuf->rect_float==NULL) return; 00920 00921 if (scopes->ok == 1 ) return; 00922 00923 if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f; 00924 00925 /* hmmmm */ 00926 if (!(ELEM(ibuf->channels, 3, 4))) return; 00927 00928 scopes->hist.channels = 3; 00929 scopes->hist.x_resolution = 256; 00930 00931 switch (scopes->wavefrm_mode) { 00932 case SCOPES_WAVEFRM_RGB: 00933 ycc_mode = -1; 00934 break; 00935 case SCOPES_WAVEFRM_LUMA: 00936 case SCOPES_WAVEFRM_YCC_JPEG: 00937 ycc_mode = BLI_YCC_JFIF_0_255; 00938 break; 00939 case SCOPES_WAVEFRM_YCC_601: 00940 ycc_mode = BLI_YCC_ITU_BT601; 00941 break; 00942 case SCOPES_WAVEFRM_YCC_709: 00943 ycc_mode = BLI_YCC_ITU_BT709; 00944 break; 00945 } 00946 00947 /* temp table to count pix value for histo */ 00948 bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); 00949 bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); 00950 bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); 00951 bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); 00952 00953 /* convert to number of lines with logarithmic scale */ 00954 scopes->sample_lines = (scopes->accuracy*0.01f) * (scopes->accuracy*0.01f) * ibuf->y; 00955 00956 if (scopes->sample_full) 00957 scopes->sample_lines = ibuf->y; 00958 00959 /* scan the image */ 00960 savedlines=0; 00961 for (c=0; c<3; c++) { 00962 scopes->minmax[c][0]=25500.0f; 00963 scopes->minmax[c][1]=-25500.0f; 00964 } 00965 00966 scopes->waveform_tot = ibuf->x*scopes->sample_lines; 00967 00968 if (scopes->waveform_1) 00969 MEM_freeN(scopes->waveform_1); 00970 if (scopes->waveform_2) 00971 MEM_freeN(scopes->waveform_2); 00972 if (scopes->waveform_3) 00973 MEM_freeN(scopes->waveform_3); 00974 if (scopes->vecscope) 00975 MEM_freeN(scopes->vecscope); 00976 00977 scopes->waveform_1= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1"); 00978 scopes->waveform_2= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2"); 00979 scopes->waveform_3= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3"); 00980 scopes->vecscope= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel"); 00981 00982 if (is_float) 00983 rf = ibuf->rect_float; 00984 else 00985 rc = (unsigned char *)ibuf->rect; 00986 00987 for (y = 0; y < ibuf->y; y++) { 00988 if (savedlines<scopes->sample_lines && y>=((savedlines)*ibuf->y)/(scopes->sample_lines+1)) { 00989 saveline=1; 00990 } else saveline=0; 00991 for (x = 0; x < ibuf->x; x++) { 00992 00993 if (is_float) { 00994 if (use_color_management) 00995 linearrgb_to_srgb_v3_v3(rgb, rf); 00996 else 00997 copy_v3_v3(rgb, rf); 00998 } 00999 else { 01000 for (c=0; c<3; c++) 01001 rgb[c] = rc[c] * INV_255; 01002 } 01003 01004 /* we still need luma for histogram */ 01005 luma = rgb_to_luma(rgb); 01006 01007 /* check for min max */ 01008 if(ycc_mode == -1 ) { 01009 for (c=0; c<3; c++) { 01010 if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c]; 01011 if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c]; 01012 } 01013 } 01014 else { 01015 rgb_to_ycc(rgb[0],rgb[1],rgb[2],&ycc[0],&ycc[1],&ycc[2], ycc_mode); 01016 for (c=0; c<3; c++) { 01017 ycc[c] *=INV_255; 01018 if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c]; 01019 if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c]; 01020 } 01021 } 01022 /* increment count for histo*/ 01023 bin_r[ get_bin_float(rgb[0]) ] += 1; 01024 bin_g[ get_bin_float(rgb[1]) ] += 1; 01025 bin_b[ get_bin_float(rgb[2]) ] += 1; 01026 bin_lum[ get_bin_float(luma) ] += 1; 01027 01028 /* save sample if needed */ 01029 if(saveline) { 01030 const float fx = (float)x / (float)ibuf->x; 01031 const int idx = 2*(ibuf->x*savedlines+x); 01032 save_sample_line(scopes, idx, fx, rgb, ycc); 01033 } 01034 01035 rf+= ibuf->channels; 01036 rc+= ibuf->channels; 01037 } 01038 if (saveline) 01039 savedlines +=1; 01040 } 01041 01042 /* convert hist data to float (proportional to max count) */ 01043 n=0; 01044 nl=0; 01045 for (x=0; x<256; x++) { 01046 if (bin_r[x] > n) 01047 n = bin_r[x]; 01048 if (bin_g[x] > n) 01049 n = bin_g[x]; 01050 if (bin_b[x] > n) 01051 n = bin_b[x]; 01052 if (bin_lum[x] > nl) 01053 nl = bin_lum[x]; 01054 } 01055 div = 1.0/(double)n; 01056 divl = 1.0/(double)nl; 01057 for (x=0; x<256; x++) { 01058 scopes->hist.data_r[x] = bin_r[x] * div; 01059 scopes->hist.data_g[x] = bin_g[x] * div; 01060 scopes->hist.data_b[x] = bin_b[x] * div; 01061 scopes->hist.data_luma[x] = bin_lum[x] * divl; 01062 } 01063 MEM_freeN(bin_r); 01064 MEM_freeN(bin_g); 01065 MEM_freeN(bin_b); 01066 MEM_freeN(bin_lum); 01067 01068 scopes->ok = 1; 01069 } 01070 01071 void scopes_free(Scopes *scopes) 01072 { 01073 if (scopes->waveform_1) { 01074 MEM_freeN(scopes->waveform_1); 01075 scopes->waveform_1 = NULL; 01076 } 01077 if (scopes->waveform_2) { 01078 MEM_freeN(scopes->waveform_2); 01079 scopes->waveform_2 = NULL; 01080 } 01081 if (scopes->waveform_3) { 01082 MEM_freeN(scopes->waveform_3); 01083 scopes->waveform_3 = NULL; 01084 } 01085 if (scopes->vecscope) { 01086 MEM_freeN(scopes->vecscope); 01087 scopes->vecscope = NULL; 01088 } 01089 } 01090 01091 void scopes_new(Scopes *scopes) 01092 { 01093 scopes->accuracy=30.0; 01094 scopes->hist.mode=HISTO_MODE_RGB; 01095 scopes->wavefrm_alpha=0.3; 01096 scopes->vecscope_alpha=0.3; 01097 scopes->wavefrm_height= 100; 01098 scopes->vecscope_height= 100; 01099 scopes->hist.height= 100; 01100 scopes->ok= 0; 01101 scopes->waveform_1 = NULL; 01102 scopes->waveform_2 = NULL; 01103 scopes->waveform_3 = NULL; 01104 scopes->vecscope = NULL; 01105 }