diff --git a/source/blender/include/BSE_editipo.h b/source/blender/include/BSE_editipo.h index 435a59f645b..d102587a563 100644 --- a/source/blender/include/BSE_editipo.h +++ b/source/blender/include/BSE_editipo.h @@ -94,6 +94,7 @@ void add_duplicate_editipo(void); void remove_doubles_ipo(void); void clean_ipo(struct Ipo *ipo, short mode); void clean_ipo_curve(struct IpoCurve *icu); +void smooth_ipo(void); void join_ipo_menu(void); void join_ipo(int mode); void ipo_snap_menu(void); diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 05fd6e6dfe2..f0a5020025a 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -3166,6 +3166,141 @@ void clean_ipo_curve(IpoCurve *icu) calchandles_ipocurve(icu); } +static void smooth_bezt_handles(BezTriple *prev, BezTriple *me, BezTriple *next) +{ + /* Smoothes (i.e. aligns) handles on the beztriple called me! + * + * The code here has been adapted from the "Smooth Ipo" + * python script (author unknown). + */ + + float ptA[2], ptB[2], ptC[2]; + float tdx, udx; + float tdy, udy; + float tx, ux; + float max_udy, max_tdy; + float slopu, slopt; + float medianSlope, slope; + float simpleudy, simpletdy; + float ty, uy; + + /* get center-points of beztriples */ + ptA[0]= prev->vec[1][0]; + ptA[1]= prev->vec[1][1]; + ptB[0]= me->vec[1][0]; + ptB[1]= me->vec[1][1]; + if (next != NULL) { + ptC[0]= next->vec[1][0]; + ptC[1]= next->vec[1][1]; + } + else { + ptC[0]= ptB[0] + 1.0f; + ptC[1]= ptB[1]; + } + + /* varios factors (are all of these needed?) */ + tdx= (ptA[0]-ptB[0]) / 3.0f; + udx= (ptC[0]-ptB[0]) / 3.0f; + tx= ptB[0] + tdx; + ux= ptB[0] + udx; + max_udy= ptC[1] - ptB[1]; + max_tdy= ptA[1] - ptB[1]; + + /* compute slopes */ + if ((ptC[0]-ptB[0])==0.0) + slopu= 0.0f; + else + slopu= (ptC[1]-ptB[1]) / (ptC[0]-ptB[0]); + if ((ptA[0]-ptB[0])==0.0) + slopt= 0.0f; + else + slopt= (ptA[1]-ptB[1]) / (ptA[0]-ptB[0]); + if ((slopu*slopt) < 0) { + udy= 0; + tdy= 0; + } + else { + /* compute median slope */ + medianSlope= (slopu+slopt) / 2.0; + simpleudy= medianSlope * udx; + simpletdy= medianSlope * tdx; + + if ((simpleudy < max_udy) && (simpletdy < max_tdy)) { + udy= simpleudy; + tdy= simpletdy; + } + else { + /* use smallest slope */ + slope = (slopu < slopt)?slopu:slopt; + slope = slope * ((slopu < 0)?-1:1); + udy= slope*udx; + tdy= slope*tdx; + } + } + + /* calculate any remaining values */ + ty= ptB[1] + tdy; + uy= ptB[1] + udy; + + /* set new values of the handles of of beztriple being acted on */ + me->vec[0][0]= tx; + me->vec[0][1]= ty; + me->vec[1][0]= ptB[0]; + me->vec[1][1]= ptB[1]; + me->vec[2][0]= ux; + me->vec[2][1]= uy; + me->vec[0][2] = me->vec[1][2] = me->vec[2][2] = 0.0f; +} + +void smooth_ipo(void) +{ + EditIpo *ei; + short ok; + int b; + + get_status_editipo(); + + ei= G.sipo->editipo; + for(b=0; btotipo; b++, ei++) { + if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) { + + ok= 0; + if(G.sipo->showkey) ok= 1; + else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2; + else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3; + + if(ok) { + IpoCurve *icu= ei->icu; + + /* check if enough points */ + if (icu->totvert <= 3) { + BezTriple *prev, *me, *next; + int i; + + for (i=1; i < icu->totvert; i++) { + /* try to get next point */ + prev = (icu->bezt + (i - 1)); + me = (icu->bezt + i); + if (i < (icu->totvert - 1)) + next = (icu->bezt + (i + 1)); + else + next = NULL; + + /* smooth handles of current beztriple (me) */ + smooth_bezt_handles(prev, me, next); + } + } + + /* recalc handles */ + calchandles_ipocurve(icu); + } + } + } + + editipo_changed(G.sipo, 1); + BIF_undo_push("Smooth IPO"); +} + void join_ipo_menu(void) { int mode = 0; diff --git a/source/blender/src/header_ipo.c b/source/blender/src/header_ipo.c index b0e64d77830..aa446fc50dc 100644 --- a/source/blender/src/header_ipo.c +++ b/source/blender/src/header_ipo.c @@ -585,6 +585,9 @@ static void do_ipo_editmenu(void *arg, int event) clean_ipo(sipo->ipo, 1); } break; + case 9: /* smooth ipo */ + smooth_ipo(); + break; } } @@ -641,6 +644,7 @@ static uiBlock *ipo_editmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Record Mouse Movement|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clean IPO Curves|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Smooth IPO Curves|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, ipo_editmenu_joinmenu, NULL, ICON_RIGHTARROW_THIN, "Join", 0, yco-=20, 120, 19, ""); @@ -707,7 +711,11 @@ static void do_ipo_viewmenu(void *arg, int event) G.v2d->flag ^= V2D_VIEWLOCK; if(G.v2d->flag & V2D_VIEWLOCK) view2d_do_locks(curarea, 0); - break; + break; + case 10: /* center view to current frame */ + center_currframe(); + scrarea_queue_winredraw(curarea); + break; } } diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 26720f825b3..4589af745a1 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -2376,7 +2376,10 @@ static void winqreadipospace(ScrArea *sa, void *spacedata, BWinEvent *evt) doredraw= 1; break; case OKEY: - clean_ipo(sipo->ipo, 1); + if(G.qual==LR_SHIFTKEY) + smooth_ipo(); + else + clean_ipo(sipo->ipo, 1); break; case RKEY: if((G.qual==0))