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