4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2005 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL/BL DUAL LICENSE BLOCK *****
39 #include "MEM_guardedalloc.h"
41 #include "DNA_color_types.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_texture_types.h"
46 #include "BKE_colortools.h"
47 #include "BKE_curve.h"
48 #include "BKE_global.h"
50 #include "BKE_image.h"
52 #include "BKE_utildefines.h"
54 #include "BLI_blenlib.h"
56 #include "BLI_threads.h"
58 #include "IMB_imbuf.h"
59 #include "IMB_imbuf_types.h"
62 void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w)
67 unsigned char *rc= rectc;
69 for(y=y1; y<y2; y++) {
70 for(x=x1; x<x2; x++, rf+=4, rc+=4) {
71 srgb[0]= linearrgb_to_srgb(rf[0]);
72 srgb[1]= linearrgb_to_srgb(rf[1]);
73 srgb[2]= linearrgb_to_srgb(rf[2]);
75 rc[0]= FTOCHAR(srgb[0]);
76 rc[1]= FTOCHAR(srgb[1]);
77 rc[2]= FTOCHAR(srgb[2]);
78 rc[3]= FTOCHAR(rf[3]);
83 void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w)
87 unsigned char *rc= rectc;
89 for(y=y1; y<y2; y++) {
90 for(x=x1; x<x2; x++, rf+=4, rc+=4) {
91 rc[0]= FTOCHAR(rf[0]);
92 rc[1]= FTOCHAR(rf[1]);
93 rc[2]= FTOCHAR(rf[2]);
94 rc[3]= FTOCHAR(rf[3]);
100 /* ********************************* color curve ********************* */
102 /* ***************** operations on full struct ************* */
104 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
108 float clipminx, clipminy, clipmaxx, clipmaxy;
110 cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
111 cumap->flag= CUMA_DO_CLIP;
112 if(tot==4) cumap->cur= 3; /* rhms, hack for 'col' curve? */
114 clipminx = MIN2(minx, maxx);
115 clipminy = MIN2(miny, maxy);
116 clipmaxx = MAX2(minx, maxx);
117 clipmaxy = MAX2(miny, maxy);
119 BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
120 cumap->clipr= cumap->curr;
122 cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
123 cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
125 for(a=0; a<tot; a++) {
126 cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE;
127 cumap->cm[a].totpoint= 2;
128 cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
130 cumap->cm[a].curve[0].x= minx;
131 cumap->cm[a].curve[0].y= miny;
132 cumap->cm[a].curve[1].x= maxx;
133 cumap->cm[a].curve[1].y= maxy;
138 void curvemapping_free(CurveMapping *cumap)
143 for(a=0; a<CM_TOT; a++) {
144 if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
145 if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
151 CurveMapping *curvemapping_copy(CurveMapping *cumap)
156 CurveMapping *cumapn= MEM_dupallocN(cumap);
157 for(a=0; a<CM_TOT; a++) {
158 if(cumap->cm[a].curve)
159 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
160 if(cumap->cm[a].table)
161 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
168 void curvemapping_set_black_white(CurveMapping *cumap, float *black, float *white)
173 VECCOPY(cumap->white, white);
175 VECCOPY(cumap->black, black);
178 if(cumap->white[a]==cumap->black[a])
179 cumap->bwmul[a]= 0.0f;
181 cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]);
185 /* ***************** operations on single curve ************* */
186 /* ********** NOTE: requires curvemapping_changed() call after ******** */
188 /* removes with flag set */
189 void curvemap_remove(CurveMap *cuma, int flag)
191 CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
194 /* well, lets keep the two outer points! */
195 cmp[0]= cuma->curve[0];
196 for(a=1, b=1; a<cuma->totpoint-1; a++) {
197 if(!(cuma->curve[a].flag & flag)) {
198 cmp[b]= cuma->curve[a];
203 cmp[b]= cuma->curve[a];
205 MEM_freeN(cuma->curve);
207 cuma->totpoint -= removed;
210 void curvemap_insert(CurveMap *cuma, float x, float y)
212 CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
213 int a, b, foundloc= 0;
215 /* insert fragments of the old one and the new point to the new curve */
217 for(a=0, b=0; a<cuma->totpoint; a++) {
218 if((x < cuma->curve[a].x) && !foundloc) {
221 cmp[a].flag= CUMA_SELECT;
225 cmp[a].x= cuma->curve[b].x;
226 cmp[a].y= cuma->curve[b].y;
227 cmp[a].flag= cuma->curve[b].flag;
228 cmp[a].flag &= ~CUMA_SELECT; /* make sure old points don't remain selected */
229 cmp[a].shorty= cuma->curve[b].shorty;
234 /* free old curve and replace it with new one */
235 MEM_freeN(cuma->curve);
239 void curvemap_reset(CurveMap *cuma, rctf *clipr, CurveMappingPreset preset)
242 MEM_freeN(cuma->curve);
245 case CURVE_PRESET_LINE: cuma->totpoint= 2; break;
246 case CURVE_PRESET_SHARP: cuma->totpoint= 3; break;
247 case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break;
248 case CURVE_PRESET_MAX: cuma->totpoint= 2; break;
251 cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points");
254 case CURVE_PRESET_LINE:
255 cuma->curve[0].x= clipr->xmin;
256 cuma->curve[0].y= clipr->ymin;
257 cuma->curve[0].flag= 0;
258 cuma->curve[1].x= clipr->xmax;
259 cuma->curve[1].y= clipr->ymax;
260 cuma->curve[1].flag= 0;
262 case CURVE_PRESET_SHARP:
265 cuma->curve[1].x= 0.33;
266 cuma->curve[1].y= 0.33;
270 case CURVE_PRESET_SMOOTH:
273 cuma->curve[1].x= 0.25;
274 cuma->curve[1].y= 0.92;
275 cuma->curve[2].x= 0.75;
276 cuma->curve[2].y= 0.08;
280 case CURVE_PRESET_MAX:
289 MEM_freeN(cuma->table);
294 /* if type==1: vector, else auto */
295 void curvemap_sethandle(CurveMap *cuma, int type)
299 for(a=0; a<cuma->totpoint; a++) {
300 if(cuma->curve[a].flag & CUMA_SELECT) {
301 if(type) cuma->curve[a].flag |= CUMA_VECTOR;
302 else cuma->curve[a].flag &= ~CUMA_VECTOR;
307 /* *********************** Making the tables and display ************** */
309 /* reduced copy of garbled calchandleNurb() code in curve.c */
310 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
312 float *p1,*p2,*p3,pt[3];
313 float dx1,dy1, dx,dy, vx,vy, len,len1,len2;
315 if(bezt->h1==0 && bezt->h2==0) return;
321 pt[0]= 2*p2[0]- p3[0];
322 pt[1]= 2*p2[1]- p3[1];
325 else p1= prev->vec[1];
329 pt[0]= 2*p2[0]- p1[0];
330 pt[1]= 2*p2[1]- p1[1];
333 else p3= next->vec[1];
338 len1= (float)sqrt(dx*dx+dy*dy);
343 len2= (float)sqrt(dx1*dx1+dy1*dy1);
345 if(len1==0.0f) len1=1.0f;
346 if(len2==0.0f) len2=1.0f;
348 if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
349 vx= dx1/len2 + dx/len1;
350 vy= dy1/len2 + dy/len1;
352 len= 2.5614f*(float)sqrt(vx*vx + vy*vy);
355 if(bezt->h1==HD_AUTO) {
357 *(p2-3)= *p2-vx*len1;
358 *(p2-2)= *(p2+1)-vy*len1;
360 if(bezt->h2==HD_AUTO) {
362 *(p2+3)= *p2+vx*len2;
363 *(p2+4)= *(p2+1)+vy*len2;
368 if(bezt->h1==HD_VECT) { /* vector */
374 if(bezt->h2==HD_VECT) {
378 *(p2+4)= *(p2+1)+dy1;
383 X is presumed to be outside first or last */
384 static float curvemap_calc_extend(CurveMap *cuma, float x, float *first, float *last)
387 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
392 if(cuma->ext_in[0]==0.0f)
393 return first[1] + cuma->ext_in[1]*10000.0f;
395 return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0];
398 else if(x >= last[0]) {
399 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
404 if(cuma->ext_out[0]==0.0f)
405 return last[1] - cuma->ext_out[1]*10000.0f;
407 return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0];
413 /* only creates a table for a single channel in CurveMapping */
414 static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
416 CurveMapPoint *cmp= cuma->curve;
418 float *fp, *allpoints, *lastpoint, curf, range;
421 if(cuma->curve==NULL) return;
423 /* default rect also is table range */
424 cuma->mintable= clipr->xmin;
425 cuma->maxtable= clipr->xmax;
427 /* hrmf... we now rely on blender ipo beziers, these are more advanced */
428 bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
430 for(a=0; a<cuma->totpoint; a++) {
431 cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
432 cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
433 bezt[a].vec[1][0]= cmp[a].x;
434 bezt[a].vec[1][1]= cmp[a].y;
435 if(cmp[a].flag & CUMA_VECTOR)
436 bezt[a].h1= bezt[a].h2= HD_VECT;
438 bezt[a].h1= bezt[a].h2= HD_AUTO;
441 for(a=0; a<cuma->totpoint; a++) {
443 calchandle_curvemap(bezt, NULL, bezt+1, 0);
444 else if(a==cuma->totpoint-1)
445 calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
447 calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
450 /* first and last handle need correction, instead of pointing to center of next/prev,
451 we let it point to the closest handle */
452 if(cuma->totpoint>2) {
453 float hlen, nlen, vec[3];
455 if(bezt[0].h2==HD_AUTO) {
457 hlen= len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
458 /* clip handle point */
459 VECCOPY(vec, bezt[1].vec[0]);
460 if(vec[0] < bezt[0].vec[1][0])
461 vec[0]= bezt[0].vec[1][0];
463 sub_v3_v3v3(vec, vec, bezt[0].vec[1]);
465 if(nlen>FLT_EPSILON) {
466 mul_v3_fl(vec, hlen/nlen);
467 add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
468 sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
472 if(bezt[a].h2==HD_AUTO) {
474 hlen= len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
475 /* clip handle point */
476 VECCOPY(vec, bezt[a-1].vec[2]);
477 if(vec[0] > bezt[a].vec[1][0])
478 vec[0]= bezt[a].vec[1][0];
480 sub_v3_v3v3(vec, vec, bezt[a].vec[1]);
482 if(nlen>FLT_EPSILON) {
483 mul_v3_fl(vec, hlen/nlen);
484 add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
485 sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
489 /* make the bezier curve */
491 MEM_freeN(cuma->table);
492 totpoint= (cuma->totpoint-1)*CM_RESOL;
493 fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table");
495 for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
496 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
497 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));
498 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));
501 /* store first and last handle for extrapolation, unit length */
502 cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0];
503 cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1];
504 range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]);
505 cuma->ext_in[0]/= range;
506 cuma->ext_in[1]/= range;
509 cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0];
510 cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1];
511 range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]);
512 cuma->ext_out[0]/= range;
513 cuma->ext_out[1]/= range;
518 range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
519 cuma->range= 1.0f/range;
521 /* now make a table with CM_TABLE equal x distances */
523 lastpoint= allpoints + 2*(totpoint-1);
524 cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
526 for(a=0; a<=CM_TABLE; a++) {
527 curf= cuma->mintable + range*(float)a;
530 /* get the first x coordinate larger than curf */
531 while(curf >= fp[0] && fp!=lastpoint) {
534 if(fp==allpoints || (curf >= fp[0] && fp==lastpoint))
535 cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
537 float fac1= fp[0] - fp[-2];
538 float fac2= fp[0] - curf;
539 if(fac1 > FLT_EPSILON)
543 cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
547 MEM_freeN(allpoints);
551 /* call when you do images etc, needs restore too. also verifies tables */
552 /* it uses a flag to prevent premul or free to happen twice */
553 void curvemapping_premultiply(CurveMapping *cumap, int restore)
558 if(cumap->flag & CUMA_PREMULLED) {
560 MEM_freeN(cumap->cm[a].table);
561 cumap->cm[a].table= cumap->cm[a].premultable;
562 cumap->cm[a].premultable= NULL;
565 cumap->flag &= ~CUMA_PREMULLED;
569 if((cumap->flag & CUMA_PREMULLED)==0) {
570 /* verify and copy */
572 if(cumap->cm[a].table==NULL)
573 curvemap_make_table(cumap->cm+a, &cumap->clipr);
574 cumap->cm[a].premultable= cumap->cm[a].table;
575 cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
576 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
579 if(cumap->cm[3].table==NULL)
580 curvemap_make_table(cumap->cm+3, &cumap->clipr);
585 for(b=0; b<=CM_TABLE; b++) {
586 cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
590 cumap->flag |= CUMA_PREMULLED;
595 static int sort_curvepoints(const void *a1, const void *a2)
597 const struct CurveMapPoint *x1=a1, *x2=a2;
599 if( x1->x > x2->x ) return 1;
600 else if( x1->x < x2->x) return -1;
604 /* ************************ more CurveMapping calls *************** */
606 /* note; only does current curvemap! */
607 void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
609 CurveMap *cuma= cumap->cm+cumap->cur;
610 CurveMapPoint *cmp= cuma->curve;
611 rctf *clipr= &cumap->clipr;
612 float thresh= 0.01f*(clipr->xmax - clipr->xmin);
613 float dx= 0.0f, dy= 0.0f;
616 /* clamp with clip */
617 if(cumap->flag & CUMA_DO_CLIP) {
618 for(a=0; a<cuma->totpoint; a++) {
619 if(cmp[a].flag & CUMA_SELECT) {
620 if(cmp[a].x < clipr->xmin)
621 dx= MIN2(dx, cmp[a].x - clipr->xmin);
622 else if(cmp[a].x > clipr->xmax)
623 dx= MAX2(dx, cmp[a].x - clipr->xmax);
624 if(cmp[a].y < clipr->ymin)
625 dy= MIN2(dy, cmp[a].y - clipr->ymin);
626 else if(cmp[a].y > clipr->ymax)
627 dy= MAX2(dy, cmp[a].y - clipr->ymax);
630 for(a=0; a<cuma->totpoint; a++) {
631 if(cmp[a].flag & CUMA_SELECT) {
639 qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
641 /* remove doubles, threshold set on 1% of default range */
642 if(rem_doubles && cuma->totpoint>2) {
643 for(a=0; a<cuma->totpoint-1; a++) {
644 dx= cmp[a].x - cmp[a+1].x;
645 dy= cmp[a].y - cmp[a+1].y;
646 if( sqrt(dx*dx + dy*dy) < thresh ) {
649 if(cmp[a+1].flag & CUMA_SELECT)
650 cmp[a].flag |= CUMA_SELECT;
654 if(cmp[a].flag & CUMA_SELECT)
655 cmp[a+1].flag |= CUMA_SELECT;
657 break; /* we assume 1 deletion per edit is ok */
660 if(a != cuma->totpoint-1)
661 curvemap_remove(cuma, 2);
663 curvemap_make_table(cuma, clipr);
666 /* table should be verified */
667 float curvemap_evaluateF(CurveMap *cuma, float value)
673 fi= (value-cuma->mintable)*cuma->range;
676 /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
677 if(fi<0.0f || fi>CM_TABLE)
678 return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
680 if(i<0) return cuma->table[0].y;
681 if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
684 return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y;
688 /* works with curve 'cur' */
689 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
691 CurveMap *cuma= cumap->cm+cur;
693 /* allocate or bail out */
694 if(cuma->table==NULL) {
695 curvemap_make_table(cuma, &cumap->clipr);
696 if(cuma->table==NULL)
699 return curvemap_evaluateF(cuma, value);
703 void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin)
705 vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
706 vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
707 vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
710 /* RGB case, no black/white points, no premult */
711 void curvemapping_evaluateRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
713 vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
714 vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
715 vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
719 /* RGB with black/white points and premult. tables are checked */
720 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
724 fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
725 vecout[0]= curvemap_evaluateF(cumap->cm, fac);
727 fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
728 vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
730 fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
731 vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
734 void colorcorrection_do_ibuf(ImBuf *ibuf, const char *profile)
736 if (ibuf->crect == NULL)
739 cmsHPROFILE imageProfile, proofingProfile;
740 cmsHTRANSFORM hTransform;
742 ibuf->crect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(int), "imbuf crect");
744 imageProfile = cmsCreate_sRGBProfile();
745 proofingProfile = cmsOpenProfileFromFile(profile, "r");
747 cmsErrorAction(LCMS_ERROR_SHOW);
749 hTransform = cmsCreateProofingTransform(imageProfile, TYPE_RGBA_8, imageProfile, TYPE_RGBA_8,
751 INTENT_ABSOLUTE_COLORIMETRIC,
752 INTENT_ABSOLUTE_COLORIMETRIC,
753 cmsFLAGS_SOFTPROOFING);
755 cmsDoTransform(hTransform, ibuf->rect, ibuf->crect, ibuf->x * ibuf->y);
757 cmsDeleteTransform(hTransform);
758 cmsCloseProfile(imageProfile);
759 cmsCloseProfile(proofingProfile);
761 ibuf->crect = ibuf->rect;
766 /* only used for image editor curves */
767 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
778 if(ibuf->rect_float==NULL)
779 IMB_float_from_rect(ibuf);
780 else if(ibuf->rect==NULL)
781 imb_addrectImBuf(ibuf);
783 if (!ibuf->rect || !ibuf->rect_float)
786 /* work on a temp buffer, so can color manage afterwards.
787 * No worse off memory wise than comp nodes */
788 tmpbuf = IMB_dupImBuf(ibuf);
790 curvemapping_premultiply(cumap, 0);
792 pix_in= ibuf->rect_float;
793 pix_out= tmpbuf->rect_float;
794 // pixc= (char *)ibuf->rect;
797 stride= ibuf->channels;
799 for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pix_in+=stride, pix_out+=4) {
801 col[0]= curvemap_evaluateF(cumap->cm, *pix_in);
803 pix_out[1]= pix_out[2]= pix_out[3]= pix_out[0]= col[0];
806 curvemapping_evaluate_premulRGBF(cumap, col, pix_in);
811 pix_out[3]= pix_in[3];
817 IMB_rect_from_float(tmpbuf);
818 SWAP(unsigned int *, tmpbuf->rect, ibuf->rect);
819 IMB_freeImBuf(tmpbuf);
822 curvemapping_premultiply(cumap, 1);
825 int curvemapping_RGBA_does_something(CurveMapping *cumap)
829 if(cumap->black[0]!=0.0f) return 1;
830 if(cumap->black[1]!=0.0f) return 1;
831 if(cumap->black[2]!=0.0f) return 1;
832 if(cumap->white[0]!=1.0f) return 1;
833 if(cumap->white[1]!=1.0f) return 1;
834 if(cumap->white[2]!=1.0f) return 1;
836 for(a=0; a<CM_TOT; a++) {
837 if(cumap->cm[a].curve) {
838 if(cumap->cm[a].totpoint!=2) return 1;
840 if(cumap->cm[a].curve[0].x != 0.0f) return 1;
841 if(cumap->cm[a].curve[0].y != 0.0f) return 1;
842 if(cumap->cm[a].curve[1].x != 1.0f) return 1;
843 if(cumap->cm[a].curve[1].y != 1.0f) return 1;
849 void curvemapping_initialize(CurveMapping *cumap)
853 if(cumap==NULL) return;
855 for(a=0; a<CM_TOT; a++) {
856 if(cumap->cm[a].table==NULL)
857 curvemap_make_table(cumap->cm+a, &cumap->clipr);
861 void curvemapping_table_RGBA(CurveMapping *cumap, float **array, int *size)
866 *array = MEM_callocN(sizeof(float)*(*size)*4, "CurveMapping");
867 curvemapping_initialize(cumap);
869 for(a=0; a<*size; a++) {
870 if(cumap->cm[0].table)
871 (*array)[a*4+0]= cumap->cm[0].table[a].y;
872 if(cumap->cm[1].table)
873 (*array)[a*4+1]= cumap->cm[1].table[a].y;
874 if(cumap->cm[2].table)
875 (*array)[a*4+2]= cumap->cm[2].table[a].y;
876 if(cumap->cm[3].table)
877 (*array)[a*4+3]= cumap->cm[3].table[a].y;