diff options
-rw-r--r-- | source/blender/blenkernel/intern/colortools.c | 74 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_color_types.h | 6 | ||||
-rw-r--r-- | source/blender/src/butspace.c | 10 | ||||
-rw-r--r-- | source/blender/src/interface_draw.c | 18 |
4 files changed, 93 insertions, 15 deletions
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 17cba6c2a94..93238137f95 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -73,6 +73,7 @@ CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, floa cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f; for(a=0; a<tot; a++) { + cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE; cumap->cm[a].totpoint= 2; cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points"); @@ -278,6 +279,37 @@ static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *nex } } +/* in X, out Y. + X is presumed to be outside first or last */ +static float curvemap_calc_extend(CurveMap *cuma, float x, float *first, float *last) +{ + if(x <= first[0]) { + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { + /* no extrapolate */ + return first[1]; + } + else { + if(cuma->ext_in[0]==0.0f) + return first[1] + cuma->ext_in[1]*10000.0f; + else + return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0]; + } + } + else if(x >= last[0]) { + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) { + /* no extrapolate */ + return last[1]; + } + else { + if(cuma->ext_out[0]==0.0f) + return last[1] - cuma->ext_out[1]*10000.0f; + else + return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0]; + } + } + return 0.0f; +} + /* only creates a table for a single channel in CurveMapping */ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) { @@ -333,6 +365,7 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) if(nlen>FLT_EPSILON) { VecMulf(vec, hlen/nlen); VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]); + VecSubf(bezt[0].vec[0], bezt[0].vec[1], vec); } } a= cuma->totpoint-1; @@ -349,6 +382,7 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) if(nlen>FLT_EPSILON) { VecMulf(vec, hlen/nlen); VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]); + VecSubf(bezt[a].vec[2], bezt[a].vec[1], vec); } } } @@ -364,8 +398,23 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) 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); } + /* store first and last handle for extrapolation, unit length */ + cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0]; + cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1]; + range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]); + cuma->ext_in[0]/= range; + cuma->ext_in[1]/= range; + + a= cuma->totpoint-1; + cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0]; + cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1]; + range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]); + cuma->ext_out[0]/= range; + cuma->ext_out[1]/= range; + + /* cleanup */ MEM_freeN(bezt); - + range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable); cuma->range= 1.0f/range; @@ -373,10 +422,8 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) fp= allpoints; lastpoint= allpoints + 2*(totpoint-1); cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table"); - cmp[0].x= cuma->mintable; - cmp[0].y= allpoints[1]; - for(a=1; a<CM_TABLE; a++) { + for(a=0; a<=CM_TABLE; a++) { curf= cuma->mintable + range*(float)a; cmp[a].x= curf; @@ -384,8 +431,8 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) while(curf >= fp[0] && fp!=lastpoint) { fp+=2; } - if(curf >= fp[0] && fp==lastpoint) - cmp[a].y= fp[1]; + if(fp==allpoints || (curf >= fp[0] && fp==lastpoint)) + cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint); else { float fac1= fp[0] - fp[-2]; float fac2= fp[0] - curf; @@ -396,8 +443,6 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1]; } } - cmp[CM_TABLE].x= cuma->maxtable; - cmp[CM_TABLE].y= allpoints[2*totpoint-1]; MEM_freeN(allpoints); cuma->table= cmp; @@ -518,11 +563,16 @@ float curvemap_evaluateF(CurveMap *cuma, float value) /* index in table */ fi= (value-cuma->mintable)*cuma->range; i= (int)fi; - if(i<0) return cuma->table[0].y; - if(i>=CM_TABLE) return cuma->table[CM_TABLE].y; - fi= fi-(float)i; - return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; + if(fi<0.0f || fi>cuma->range) + return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x); + else { + if(i<0) return cuma->table[0].y; + if(i>=CM_TABLE) return cuma->table[CM_TABLE].y; + + fi= fi-(float)i; + return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; + } } /* works with curve 'cur' */ diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 9aae71b9cc9..32cbc39523b 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -53,11 +53,15 @@ typedef struct CurveMap { float range; /* quick multiply value for reading table */ float mintable, maxtable; /* the x-axis range for the table */ + float ext_in[2], ext_out[2]; /* for extrapolated curves, the direction vector */ CurveMapPoint *curve; /* actual curve */ CurveMapPoint *table; /* display and evaluate table */ CurveMapPoint *premultable; /* for RGB curves, premulled table */ } CurveMap; +/* cuma->flag */ +#define CUMA_EXTEND_EXTRAPOLATE 1 + typedef struct CurveMapping { int flag, cur; /* cur; for buttons, to show active curve */ @@ -68,7 +72,7 @@ typedef struct CurveMapping { float bwmul[3], padf; /* black/white point multiply value, for speed */ } CurveMapping; -/* cumap->flag */ +/* cumapping->flag */ #define CUMA_DO_CLIP 1 #define CUMA_PREMULLED 2 diff --git a/source/blender/src/butspace.c b/source/blender/src/butspace.c index a4a8a55aac3..507e89b3122 100644 --- a/source/blender/src/butspace.c +++ b/source/blender/src/butspace.c @@ -403,6 +403,14 @@ static void curvemap_tools_dofunc(void *cumap_v, int event) curvemap_sethandle(cuma, 0); curvemapping_changed(cumap, 0); break; + case 4: /* extend horiz */ + cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + curvemapping_changed(cumap, 0); + break; + case 5: /* extend extrapolate */ + cuma->flag |= CUMA_EXTEND_EXTRAPOLATE; + curvemapping_changed(cumap, 0); + break; } addqueue(curarea->win, REDRAW, 1); } @@ -418,6 +426,8 @@ static uiBlock *curvemap_tools_func(void *cumap_v) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, ""); uiBlockSetDirection(block, UI_RIGHT); diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c index f42d16a6d5a..2d5d8f8a483 100644 --- a/source/blender/src/interface_draw.c +++ b/source/blender/src/interface_draw.c @@ -2187,13 +2187,27 @@ static void ui_draw_but_CURVE(uiBut *but) curvemapping_changed(cumap, 0); /* 0 = no remove doubles */ cmp= cuma->table; - glVertex2f(but->x1, but->y1 + zoomy*(cmp[0].y-offsy)); /* first point */ + /* first point */ + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) + glVertex2f(but->x1, but->y1 + zoomy*(cmp[0].y-offsy)); + else { + fx= but->x1 + zoomx*(cmp[0].x-offsx + cuma->ext_in[0]); + fy= but->y1 + zoomy*(cmp[0].y-offsy + cuma->ext_in[1]); + glVertex2f(fx, fy); + } for(a=0; a<=CM_TABLE; a++) { fx= but->x1 + zoomx*(cmp[a].x-offsx); fy= but->y1 + zoomy*(cmp[a].y-offsy); glVertex2f(fx, fy); } - glVertex2f(but->x2, but->y1 + zoomy*(cmp[CM_TABLE].y-offsy)); /* last point */ + /* last point */ + if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) + glVertex2f(but->x2, but->y1 + zoomy*(cmp[CM_TABLE].y-offsy)); + else { + fx= but->x1 + zoomx*(cmp[CM_TABLE].x-offsx - cuma->ext_out[0]); + fy= but->y1 + zoomy*(cmp[CM_TABLE].y-offsy - cuma->ext_out[1]); + glVertex2f(fx, fy); + } glEnd(); /* the points, use aspect to make them visible on edges */ |