diff options
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 42 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframes_edit.h | 6 | ||||
-rw-r--r-- | source/blender/editors/space_ipo/ipo_draw.c | 4 | ||||
-rw-r--r-- | source/blender/editors/space_ipo/ipo_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_ipo/ipo_select.c | 48 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.c | 10 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 718 |
7 files changed, 727 insertions, 103 deletions
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 66049d5e5f7..ad845f45f01 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -38,7 +38,6 @@ #include "DNA_action_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" -#include "DNA_ipo_types.h" // XXX to be phased out #include "DNA_key_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" @@ -56,7 +55,7 @@ /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data. * * Two API functions are defined for actually performing the operations on the data: - * ipo_keys_bezier_loop() and icu_keys_bezier_loop() + * ANIM_fcurve_keys_bezier_loop() * which take the data they operate on, a few callbacks defining what operations to perform. * * As operators which work on keyframes usually apply the same operation on all BezTriples in @@ -84,6 +83,10 @@ short ANIM_fcurve_keys_bezier_loop(BeztEditData *bed, FCurve *fcu, BeztEditFunc BezTriple *bezt; int b; + /* sanity check */ + if (fcu == NULL) + return 0; + /* if function to apply to bezier curves is set, then loop through executing it on beztriples */ if (bezt_cb) { /* if there's a validation func, include that check in the loop @@ -233,6 +236,21 @@ static short ok_bezier_value(BeztEditData *bed, BezTriple *bezt) return IS_EQ(bezt->vec[1][1], bed->f1); } +static short ok_bezier_valuerange(BeztEditData *bed, BezTriple *bezt) +{ + /* value range is stored in float properties */ + return ((bezt->vec[1][1] > bed->f1) && (bezt->vec[1][1] < bed->f2)); +} + +static short ok_bezier_region(BeztEditData *bed, BezTriple *bezt) +{ + /* rect is stored in data property (it's of type rectf, but may not be set) */ + if (bed->data) + return BLI_in_rctf(bed->data, bezt->vec[1][0], bezt->vec[1][1]); + else + return 0; +} + BeztEditFunc ANIM_editkeyframes_ok(short mode) { @@ -242,10 +260,14 @@ BeztEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_frame; case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */ return ok_bezier_framerange; - case BEZT_OK_SELECTED: /* only if bezt is selected */ + case BEZT_OK_SELECTED: /* only if bezt is selected (self) */ return ok_bezier_selected; case BEZT_OK_VALUE: /* only if bezt value matches (float) */ return ok_bezier_value; + case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */ + return ok_bezier_valuerange; + case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */ + return ok_bezier_region; default: /* nothing was ok */ return NULL; } @@ -355,7 +377,7 @@ static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt) } /* Note: for markers case, need to set global vars (eww...) */ -// calchandles_ipocurve +// calchandles_fcurve BeztEditFunc ANIM_editkeyframes_mirror(short type) { switch (type) { @@ -437,7 +459,7 @@ static short set_bezier_free(BeztEditData *bed, BezTriple *bezt) } /* Set all Bezier Handles to a single type */ -// calchandles_ipocurve +// calchandles_fcurve BeztEditFunc ANIM_editkeyframes_handles(short code) { switch (code) { @@ -460,21 +482,21 @@ BeztEditFunc ANIM_editkeyframes_handles(short code) static short set_bezt_constant(BeztEditData *bed, BezTriple *bezt) { if (bezt->f2 & SELECT) - bezt->ipo= IPO_CONST; + bezt->ipo= BEZT_IPO_CONST; return 0; } static short set_bezt_linear(BeztEditData *bed, BezTriple *bezt) { if (bezt->f2 & SELECT) - bezt->ipo= IPO_LIN; + bezt->ipo= BEZT_IPO_LIN; return 0; } static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) { if (bezt->f2 & SELECT) - bezt->ipo= IPO_BEZ; + bezt->ipo= BEZT_IPO_BEZ; return 0; } @@ -483,9 +505,9 @@ static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) BeztEditFunc ANIM_editkeyframes_ipo(short code) { switch (code) { - case IPO_CONST: /* constant */ + case BEZT_IPO_CONST: /* constant */ return set_bezt_constant; - case IPO_LIN: /* linear */ + case BEZT_IPO_LIN: /* linear */ return set_bezt_linear; default: /* bezier */ return set_bezt_bezier; diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 8fd5a0152c9..0564d83bccd 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -53,6 +53,8 @@ typedef enum eEditKeyframes_Validate { BEZT_OK_FRAMERANGE, BEZT_OK_SELECTED, BEZT_OK_VALUE, + BEZT_OK_VALUERANGE, + BEZT_OK_REGION, } eEditKeyframes_Validate; /* ------------ */ @@ -89,7 +91,7 @@ typedef enum eEditKeyframes_Mirror { typedef struct BeztEditData { ListBase list; /* temp list for storing custom list of data to check */ struct Scene *scene; /* pointer to current scene - many tools need access to cfra/etc. */ - void *data; /* pointer to custom data - usually 'Object', but could be other types too */ + void *data; /* pointer to custom data - usually 'Object' but also 'rectf', but could be other types too */ float f1, f2; /* storage of times/values as 'decimals' */ int i1, i2; /* storage of times/values/flags as 'whole' numbers */ } BeztEditData; @@ -126,7 +128,7 @@ BeztEditFunc ANIM_editkeyframes_ipo(short mode); void delete_fcurve_key(struct FCurve *fcu, int index, short do_recalc); void delete_fcurve_keys(struct FCurve *fcu); -void duplicate_fcurve_keys(struct FCurve *fcu); // XXX fixme... +void duplicate_fcurve_keys(struct FCurve *fcu); void clean_fcurve(struct FCurve *fcu, float thresh); void smooth_fcurve(struct FCurve *fcu, short mode); diff --git a/source/blender/editors/space_ipo/ipo_draw.c b/source/blender/editors/space_ipo/ipo_draw.c index a1c0f37506c..7ec615b83a3 100644 --- a/source/blender/editors/space_ipo/ipo_draw.c +++ b/source/blender/editors/space_ipo/ipo_draw.c @@ -617,7 +617,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) /* map ipo-points for drawing if scaled F-Curve */ if (nob) - ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0); /* draw curve - we currently calculate colour on the fly, but that should probably be done in advance instead */ col= ipo_rainbow(i, items); @@ -631,7 +631,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) /* undo mapping of keyframes for drawing if scaled F-Curve */ if (nob) - ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 0); } /* free list of curves */ diff --git a/source/blender/editors/space_ipo/ipo_ops.c b/source/blender/editors/space_ipo/ipo_ops.c index fd825276333..c9988d41413 100644 --- a/source/blender/editors/space_ipo/ipo_ops.c +++ b/source/blender/editors/space_ipo/ipo_ops.c @@ -144,7 +144,7 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) #endif // XXX code to be sanitied for new system /* transform system */ - transform_keymap_for_space(wm, keymap, SPACE_IPO); + transform_keymap_for_space(wm, keymap, /*SPACE_IPO*/SPACE_ACTION); // xxx } /* --------------- */ diff --git a/source/blender/editors/space_ipo/ipo_select.c b/source/blender/editors/space_ipo/ipo_select.c index 35a94af106d..dbc69db4e08 100644 --- a/source/blender/editors/space_ipo/ipo_select.c +++ b/source/blender/editors/space_ipo/ipo_select.c @@ -184,21 +184,17 @@ void GRAPHEDIT_OT_keyframes_deselectall (wmOperatorType *ot) /* ******************** Border Select Operator **************************** */ /* This operator currently works in one of three ways: - * -> BKEY - 1) all keyframes within region are selected (GRAPHKEYS_BORDERSEL_ALLKEYS) + * -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION) * -> ALT-BKEY - depending on which axis of the region was larger... - * -> 2) x-axis, so select all frames within frame range (GRAPHKEYS_BORDERSEL_FRAMERANGE) - * -> 3) y-axis, so select all frames within channels that region included (GRAPHKEYS_BORDERSEL_CHANNELS) + * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) + * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) */ -/* defines for borderselect mode */ -enum { - GRAPHKEYS_BORDERSEL_ALLKEYS = 0, - GRAPHKEYS_BORDERSEL_FRAMERANGE, - GRAPHKEYS_BORDERSEL_CHANNELS, -} egraphkeys_BorderSelect_Mode; - - -static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode) +/* Borderselect only selects keyframes now, as overshooting handles often get caught too, + * which means that they may be inadvertantly moved as well. + * Also, for convenience, handles should get same status as keyframe (if it was within bounds) + */ +static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, short selectmode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -210,30 +206,27 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short rctf rectf; /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ - UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax); + UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax); /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE); + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* get beztriple editing/validation funcs */ select_cb= ANIM_editkeyframes_select(selectmode); + ok_cb= ANIM_editkeyframes_ok(mode); - if (ELEM(mode, GRAPHKEYS_BORDERSEL_FRAMERANGE, GRAPHKEYS_BORDERSEL_ALLKEYS)) - ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); - else - ok_cb= NULL; - /* init editing data */ memset(&bed, 0, sizeof(BeztEditData)); + bed.data= ▭ /* loop over data, doing border select */ for (ale= anim_data.first; ale; ale= ale->next) { Object *nob= ANIM_nla_mapping_get(ac, ale); /* set horizontal range (if applicable) */ - if (ELEM(mode, GRAPHKEYS_BORDERSEL_FRAMERANGE, GRAPHKEYS_BORDERSEL_ALLKEYS)) { + if (mode != BEZT_OK_VALUERANGE) { /* if channel is mapped in NLA, apply correction */ if (nob) { bed.f1= get_action_frame(nob, rectf.xmin); @@ -245,7 +238,8 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short } } - // xxx... select code... + /* select keyframes that are in the appropriate places */ + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); } /* cleanup */ @@ -285,15 +279,15 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) * used for tweaking timing when "blocking", while channels is not that useful... */ if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin)) - mode= GRAPHKEYS_BORDERSEL_FRAMERANGE; - //else - // mode= GRAPHKEYS_BORDERSEL_CHANNELS; + mode= BEZT_OK_FRAMERANGE; + else + mode= BEZT_OK_VALUERANGE; } else - mode= GRAPHKEYS_BORDERSEL_ALLKEYS; + mode= BEZT_OK_REGION; /* apply borderselect action */ - borderselect_action(&ac, rect, mode, selectmode); + borderselect_graphkeys(&ac, rect, mode, selectmode); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ef767a04728..a55d46f9a64 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -352,6 +352,16 @@ static void viewRedrawForce(bContext *C, TransInfo *t) else ED_area_tag_redraw(t->sa); } + else if (t->spacetype == SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; + + // TRANSFORM_FIX_ME + if (sipo->lock) { + // whole window... + } + else + ED_area_tag_redraw(t->sa); + } else if(t->spacetype == SPACE_NODE) { //ED_area_tag_redraw(t->sa); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 4fc711babae..8532dda02aa 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2639,45 +2639,6 @@ int clipUVTransform(TransInfo *t, float *vec, int resize) return 0; } -/* ********************* IPO EDITOR ************************* */ - -/* for IPO Editor transform - but actual creation of transform structures is not performed here - * due to bad globals that would need to be imported specially for this - */ -static void createTransIpoData(bContext *C, TransInfo *t) -{ - // TRANSFORM_FIX_ME -#if 0 - /* in editipo.c due to some globals that are defined in that file... */ - make_ipo_transdata(t); -#endif -} - -/* this function is called on recalcData to apply the transforms applied - * to the transdata on to the actual keyframe data - */ -void flushTransIpoData(TransInfo *t) -{ -#if 0 // TRANSFORM_FIX_ME - TransData2D *td; - int a; - - /* flush to 2d vector from internally used 3d vector */ - for (a=0, td= t->data2d; a<t->total; a++, td++) { - // FIXME: autosnap needs to be here... - - /* we need to unapply the nla-scaling from the time in some situations */ - if (NLA_IPO_SCALED) - td->loc2d[0]= get_action_frame(OBACT, td->loc[0]); - else - td->loc2d[0]= td->loc[0]; - - /* when the icu that point comes from is a bitflag holder, don't allow adjusting values */ - if ((t->data[a].flag & TD_TIMEONLY)==0) - td->loc2d[1]= td->loc[1]; - } -#endif -} /* ********************* ACTION/NLA EDITOR ****************** */ @@ -3162,6 +3123,608 @@ static void createTransActionData(bContext *C, TransInfo *t) BLI_freelistN(&anim_data); } +/* ********************* GRAPH EDITOR ************************* */ + +#if 0 // GRAPH EDIT TO PORT + +/* Helper function for make_ipo_transdata, which is reponsible for associating + * source data with transform data + */ +static void bezt_to_transdata (TransData *td, TransData2D *td2d, float *loc, float *cent, short selected, short ishandle, short onlytime) +{ + /* New location from td gets dumped onto the old-location of td2d, which then + * gets copied to the actual data at td2d->loc2d (bezt->vec[n]) + * + * Due to NLA scaling, we apply NLA scaling to some of the verts here, + * and then that scaling will be undone after transform is done. + */ + + if (NLA_IPO_SCALED) { + td2d->loc[0] = get_action_frame_inv(OBACT, loc[0]); + td2d->loc[1] = loc[1]; + td2d->loc[2] = 0.0f; + td2d->loc2d = loc; + + /*td->flag = 0;*/ /* can be set beforehand, else make sure its set to 0 */ + td->loc = td2d->loc; + td->center[0] = get_action_frame_inv(OBACT, cent[0]); + td->center[1] = cent[1]; + td->center[2] = 0.0f; + + VECCOPY(td->iloc, td->loc); + } + else { + td2d->loc[0] = loc[0]; + td2d->loc[1] = loc[1]; + td2d->loc[2] = 0.0f; + td2d->loc2d = loc; + + /*td->flag = 0;*/ /* can be set beforehand, else make sure its set to 0 */ + td->loc = td2d->loc; + VECCOPY(td->center, cent); + VECCOPY(td->iloc, td->loc); + } + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext= NULL; td->tdi= NULL; td->val= NULL; + + if (selected) { + td->flag |= TD_SELECTED; + td->dist= 0.0; + } + else + td->dist= MAXFLOAT; + + if (onlytime) + td->flag |= TD_TIMEONLY; + + if (ishandle) + td->flag |= TD_NOTIMESNAP; + + Mat3One(td->mtx); + Mat3One(td->smtx); +} + +/* This function is called by createTransIpoData and remake_ipo_transdata to + * create the TransData and TransData2D arrays for transform. The costly counting + * stage is only performed for createTransIpoData case, and is indicated by t->total==-1; + */ +void make_ipo_transdata (TransInfo *t) +{ + TransData *td = NULL; + TransData2D *td2d = NULL; + + EditIpo *ei; + BezTriple *bezt, *prevbezt; + int a, b; + + /* countsel and propmode are used for proportional edit, which is not yet available */ + int count=0/*, countsel=0*/; + /*int propmode = t->flag & T_PROP_EDIT;*/ + + /* count data and allocate memory (if needed) */ + if (t->total == 0) { + /* count data first */ + if (totipo_vertsel) { + /* we're probably in editmode, so only selected verts */ + if (G.v2d->around == V3D_LOCAL) { + /* we're in editmode, but we need to count the number of selected handles only */ + ei= G.sipo->editipo; + for (a=0; a<G.sipo->totipo; a++, ei++) { + if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) { + IpoCurve *icu= ei->icu; + + if (icu->bezt) { + bezt= icu->bezt; + for (b=0; b < icu->totvert; b++, bezt++) { + if (bezt->ipo == IPO_BEZ) { + if (bezt->f1 & SELECT) count++; + if (bezt->f2 & SELECT) count++; + } + else if (bezt->f2 & SELECT) count++; + } + } + } + } + if (count==0) return; + } + else + count= totipo_vertsel; + } + else if (totipo_edit==0 && totipo_sel!=0) { + /* we're not in editmode, so entire curves get moved */ + ei= G.sipo->editipo; + for (a=0; a<G.sipo->totipo; a++, ei++) { + if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) { + IpoCurve *icu= ei->icu; + + if (icu->bezt) { + if (icu->ipo == IPO_MIXED) { + bezt= icu->bezt; + for (b=0; b < icu->totvert; b++, bezt++) { + if (bezt->ipo == IPO_BEZ) count += 3; + else count++; + } + } + else if (icu->ipo == IPO_BEZ) + count+= 3*icu->totvert; + else + count+= icu->totvert; + } + else + count+= icu->totvert; + } + } + if (count==0) return; + } + else { + /* this case should not happen */ + return; + } + + /* memory allocation */ + /*t->total= (propmode)? count: countsel;*/ + t->total= count; + t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (IPO Editor)"); + /* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */ + t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransData2D (IPO Editor)"); + } + + td= t->data; + td2d= t->data2d; + + /* add verts */ + if (totipo_vertsel) { + /* we're probably in editmode, so only selected verts */ + ei= G.sipo->editipo; + for (a=0; a<G.sipo->totipo; a++, ei++) { + /* only consider those curves that are visible and are being edited/used for showkeys */ + if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) { + if ((ei->flag & IPO_EDIT) || (G.sipo->showkey)) { + IpoCurve *icu= ei->icu; + + if (icu->bezt) { + short onlytime= (ei->disptype==IPO_DISPBITS) ? 1 : (G.sipo->showkey) ? 1 : 0; + + bezt= icu->bezt; + prevbezt= NULL; + + for (b=0; b < icu->totvert; b++, prevbezt=bezt, bezt++) { + TransDataCurveHandleFlags *hdata = NULL; + short h1=1, h2=1; + + /* only include handles if selected, and interpolaton mode uses beztriples */ + if ( (!prevbezt && (bezt->ipo==IPO_BEZ)) || (prevbezt && (prevbezt->ipo==IPO_BEZ)) ) { + if (bezt->f1 & SELECT) { + hdata = initTransDataCurveHandes(td, bezt); + bezt_to_transdata(td++, td2d++, bezt->vec[0], bezt->vec[1], 1, 1, onlytime); + } + else + h1= 0; + } + if (bezt->ipo==IPO_BEZ) { + if (bezt->f3 & SELECT) { + if (hdata==NULL) + hdata = initTransDataCurveHandes(td, bezt); + bezt_to_transdata(td++, td2d++, bezt->vec[2], bezt->vec[1], 1, 1, onlytime); + } + else + h2= 0; + } + + /* only include main vert if selected */ + if (bezt->f2 & SELECT) { + /* if scaling around individuals centers, do no include keyframes */ + if (G.v2d->around != V3D_LOCAL) { + /* if handles were not selected, store their selection status */ + if (!(bezt->f1 & SELECT) && !(bezt->f3 & SELECT)) { + if (hdata == NULL) + hdata = initTransDataCurveHandes(td, bezt); + } + + bezt_to_transdata(td++, td2d++, bezt->vec[1], bezt->vec[1], 1, 0, onlytime); + } + + /* special hack (must be done after initTransDataCurveHandes(), as that stores handle settings to restore...): + * - Check if we've got entire BezTriple selected and we're scaling/rotating that point, + * then check if we're using auto-handles. + * - If so, change them auto-handles to aligned handles so that handles get affected too + */ + if ((bezt->h1 == HD_AUTO) && (bezt->h2 == HD_AUTO) && ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { + if (h1 && h2) { + bezt->h1= HD_ALIGN; + bezt->h2= HD_ALIGN; + } + } + } + } + + /* Sets handles based on the selection */ + testhandles_ipocurve(ei->icu); + } + } + } + } + } + else if (totipo_edit==0 && totipo_sel!=0) { + /* we're not in editmode, so entire curves get moved */ + ei= G.sipo->editipo; + for (a=0; a<G.sipo->totipo; a++, ei++) { + /* only include curves that are visible and selected */ + if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) { + IpoCurve *icu= ei->icu; + + if (icu->bezt) { + short onlytime= (ei->disptype==IPO_DISPBITS) ? 1 : (G.sipo->showkey) ? 1 : 0; + + bezt= icu->bezt; + prevbezt= NULL; + + for (b=0; b < icu->totvert; b++, prevbezt=bezt, bezt++) { + /* only include handles if interpolation mode is bezier is relevant */ + if ( (!prevbezt && (bezt->ipo==IPO_BEZ)) || (prevbezt && (prevbezt->ipo==IPO_BEZ)) ) + bezt_to_transdata(td++, td2d++, bezt->vec[0], bezt->vec[1], 1, 1,onlytime); + if (bezt->ipo==IPO_BEZ) + bezt_to_transdata(td++, td2d++, bezt->vec[2], bezt->vec[1], 1, 1, onlytime); + + /* always include the main handle */ + bezt_to_transdata(td++, td2d++, bezt->vec[1], bezt->vec[1], 1, 0, onlytime); + } + } + } + } + } +} + +/* ------------------------ */ + +/* struct for use in re-sorting BezTriples during IPO transform */ +typedef struct BeztMap { + BezTriple *bezt; + int oldIndex; /* index of bezt in icu->bezt array before sorting */ + int newIndex; /* index of bezt in icu->bezt array after sorting */ + short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */ + char pipo, cipo; /* interpolation of current and next segments */ +} BeztMap; + + +/* This function converts an IpoCurve's BezTriple array to a BeztMap array + * NOTE: this allocates memory that will need to get freed later + */ +static BeztMap *bezt_to_beztmaps (BezTriple *bezts, int totvert) +{ + BezTriple *bezt= bezts; + BezTriple *prevbezt= NULL; + BeztMap *bezm, *bezms; + int i; + + /* allocate memory for this array */ + if (totvert==0 || bezts==NULL) + return NULL; + bezm= bezms= MEM_callocN(sizeof(BeztMap)*totvert, "BeztMaps"); + + /* assign beztriples to beztmaps */ + for (i=0; i < totvert; i++, bezm++, prevbezt=bezt, bezt++) { + bezm->bezt= bezt; + + bezm->oldIndex= i; + bezm->newIndex= i; + + bezm->pipo= (prevbezt) ? prevbezt->ipo : bezt->ipo; + bezm->cipo= bezt->ipo; + } + + return bezms; +} + +/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */ +static void sort_time_beztmaps (BeztMap *bezms, int totvert) +{ + BeztMap *bezm; + int i, ok= 1; + + /* keep repeating the process until nothing is out of place anymore */ + while (ok) { + ok= 0; + + bezm= bezms; + i= totvert; + while (i--) { + /* is current bezm out of order (i.e. occurs later than next)? */ + if (i > 0) { + if (bezm->bezt->vec[1][0] > (bezm+1)->bezt->vec[1][0]) { + bezm->newIndex++; + (bezm+1)->newIndex--; + + SWAP(BeztMap, *bezm, *(bezm+1)); + + ok= 1; + } + } + + /* do we need to check if the handles need to be swapped? + * optimisation: this only needs to be performed in the first loop + */ + if (bezm->swapHs == 0) { + if ( (bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) && + (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0]) ) + { + /* handles need to be swapped */ + bezm->swapHs = 1; + } + else { + /* handles need to be cleared */ + bezm->swapHs = -1; + } + } + + bezm++; + } + } +} + +/* This function firstly adjusts the pointers that the transdata has to each BezTriple*/ +static void beztmap_to_data (TransInfo *t, EditIpo *ei, BeztMap *bezms, int totvert) +{ + BezTriple *bezts = ei->icu->bezt; + BeztMap *bezm; + TransData2D *td; + int i, j; + char *adjusted; + + /* dynamically allocate an array of chars to mark whether an TransData's + * pointers have been fixed already, so that we don't override ones that are + * already done + */ + adjusted= MEM_callocN(t->total, "beztmap_adjusted_map"); + + /* for each beztmap item, find if it is used anywhere */ + bezm= bezms; + for (i= 0; i < totvert; i++, bezm++) { + /* loop through transdata, testing if we have a hit + * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped... + */ + td= t->data2d; + for (j= 0; j < t->total; j++, td++) { + /* skip item if already marked */ + if (adjusted[j] != 0) continue; + + if (totipo_vertsel) { + /* only selected verts */ + if (bezm->pipo == IPO_BEZ) { + if (bezm->bezt->f1 & SELECT) { + if (td->loc2d == bezm->bezt->vec[0]) { + if (bezm->swapHs == 1) + td->loc2d= (bezts + bezm->newIndex)->vec[2]; + else + td->loc2d= (bezts + bezm->newIndex)->vec[0]; + adjusted[j] = 1; + } + } + } + if (bezm->cipo == IPO_BEZ) { + if (bezm->bezt->f3 & SELECT) { + if (td->loc2d == bezm->bezt->vec[2]) { + if (bezm->swapHs == 1) + td->loc2d= (bezts + bezm->newIndex)->vec[0]; + else + td->loc2d= (bezts + bezm->newIndex)->vec[2]; + adjusted[j] = 1; + } + } + } + if (bezm->bezt->f2 & SELECT) { + if (td->loc2d == bezm->bezt->vec[1]) { + td->loc2d= (bezts + bezm->newIndex)->vec[1]; + adjusted[j] = 1; + } + } + } + else { + /* whole curve */ + if (bezm->pipo == IPO_BEZ) { + if (td->loc2d == bezm->bezt->vec[0]) { + if (bezm->swapHs == 1) + td->loc2d= (bezts + bezm->newIndex)->vec[2]; + else + td->loc2d= (bezts + bezm->newIndex)->vec[0]; + adjusted[j] = 1; + } + } + if (bezm->cipo == IPO_BEZ) { + if (td->loc2d == bezm->bezt->vec[2]) { + if (bezm->swapHs == 1) + td->loc2d= (bezts + bezm->newIndex)->vec[0]; + else + td->loc2d= (bezts + bezm->newIndex)->vec[2]; + adjusted[j] = 1; + } + } + if (td->loc2d == bezm->bezt->vec[1]) { + td->loc2d= (bezts + bezm->newIndex)->vec[1]; + adjusted[j] = 1; + } + } + } + + } + + /* free temp memory used for 'adjusted' array */ + MEM_freeN(adjusted); +} + +/* This function is called by recalcData during the Transform loop to recalculate + * the handles of curves and sort the keyframes so that the curves draw correctly. + * It is only called if some keyframes have moved out of order. + */ +void remake_ipo_transdata (TransInfo *t) +{ + EditIpo *ei; + int a; + + /* sort and reassign verts */ + ei= G.sipo->editipo; + for (a=0; a<G.sipo->totipo; a++, ei++) { + if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) { + if (ei->icu->bezt) { + BeztMap *bezm; + + /* adjust transform-data pointers */ + bezm= bezt_to_beztmaps(ei->icu->bezt, ei->icu->totvert); + sort_time_beztmaps(bezm, ei->icu->totvert); + beztmap_to_data(t, ei, bezm, ei->icu->totvert); + + /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */ + sort_time_ipocurve(ei->icu); + + /* free mapping stuff */ + MEM_freeN(bezm); + + /* make sure handles are all set correctly */ + testhandles_ipocurve(ei->icu); + } + } + } + + /* remake ipokeys */ + if (G.sipo->showkey) make_ipokey(); +} +#endif // GRAPHEDIT TO PORT + +static void createTransGraphEditData(bContext *C, TransInfo *t) +{ + Scene *scene= CTX_data_scene(C); + TransData *td = NULL; + + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + int count=0; + float cfra; + char side; + + /* determine what type of data we are operating on */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* which side of the current frame should be allowed */ + if (t->mode == TFM_TIME_EXTEND) { + /* only side on which mouse is gets transformed */ + float xmouse, ymouse; + + UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse); + side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side + } + else { + /* normal transform - both sides of current frame are considered */ + side = 'B'; + } + + /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(&ac, ale); + + /* convert current-frame to action-time (slightly less accurate, espcially under + * higher scaling ratios, but is faster than converting all points) + */ + if (nob) + cfra = get_action_frame(nob, (float)CFRA); + else + cfra = (float)CFRA; + + count += count_fcurve_keys(ale->key_data, side, cfra); + } + + /* stop if trying to build list if nothing selected */ + if (count == 0) { + /* cleanup temp list */ + BLI_freelistN(&anim_data); + return; + } + + /* allocate memory for data */ + t->total= count; + + t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)"); + td= t->data; + + if (t->mode == TFM_TIME_SLIDE) + t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max"); + + /* loop 2: build transdata array */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(&ac, ale); + FCurve *fcu= (FCurve *)ale->key_data; + + /* convert current-frame to action-time (slightly less accurate, espcially under + * higher scaling ratios, but is faster than converting all points) + */ + if (nob) + cfra = get_action_frame(nob, (float)CFRA); + else + cfra = (float)CFRA; + + td= FCurveToTransData(td, fcu, nob, side, cfra); // XXX... this doesn't do points! + } + + /* check if we're supposed to be setting minx/maxx for TimeSlide */ + if (t->mode == TFM_TIME_SLIDE) { + float min=999999999.0f, max=-999999999.0f; + int i; + + td= (t->data + 1); + for (i=1; i < count; i+=3, td+=3) { + if (min > *(td->val)) min= *(td->val); + if (max < *(td->val)) max= *(td->val); + } + + /* minx/maxx values used by TimeSlide are stored as a + * calloced 2-float array in t->customData. This gets freed + * in postTrans (T_FREE_CUSTOMDATA). + */ + *((float *)(t->customData)) = min; + *((float *)(t->customData) + 1) = max; + } + + /* cleanup temp list */ + BLI_freelistN(&anim_data); +} + + +/* this function is called on recalcData to apply the transforms applied + * to the transdata on to the actual keyframe data + */ +void flushTransIpoData(TransInfo *t) +{ +#if 0 // TRANSFORM_FIX_ME + TransData2D *td; + int a; + + /* flush to 2d vector from internally used 3d vector */ + for (a=0, td= t->data2d; a<t->total; a++, td++) { + // FIXME: autosnap needs to be here... + + /* we need to unapply the nla-scaling from the time in some situations */ + if (NLA_IPO_SCALED) + td->loc2d[0]= get_action_frame(OBACT, td->loc[0]); + else + td->loc2d[0]= td->loc[0]; + + /* when the icu that point comes from is a bitflag holder, don't allow adjusting values */ + if ((t->data[a].flag & TD_TIMEONLY)==0) + td->loc2d[1]= td->loc[1]; + } +#endif +} + /* **************** IpoKey stuff, for Object TransData ********** */ @@ -4226,12 +4789,65 @@ void special_aftertrans_update(TransInfo *t) } #endif // XXX future of this is still not clear - /* make sure all IPO-curves are set correctly */ + /* make sure all F-Curves are set correctly */ ANIM_editkeyframes_refresh(&ac); /* clear flag that was set for time-slide drawing */ saction->flag &= ~SACTION_MOVING; } + else if (t->spacetype == SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; + Scene *scene; + bAnimContext ac; + + /* initialise relevant anim-context 'context' data from TransInfo data */ + /* NOTE: sync this with the code in ANIM_animdata_get_context() */ + memset(&ac, 0, sizeof(bAnimContext)); + + scene= ac.scene= t->scene; + ob= ac.obact= OBACT; + ac.sa= t->sa; + ac.ar= t->ar; + ac.spacetype= (t->sa)? t->sa->spacetype : 0; + ac.regiontype= (t->ar)? t->ar->regiontype : 0; + + if (ANIM_animdata_context_getdata(&ac) == 0) + return; + + if (ac.datatype) + { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + short filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE); + + /* get channels to work on */ + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* these should all be ipo-blocks */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(&ac, ale); + FCurve *fcu= (FCurve *)ale->key_data; + + if ( (sipo->flag & SIPO_NOTRANSKEYCULL)==0 && + ((cancelled == 0) || (duplicate)) ) + { + if (nob) { + ANIM_nla_mapping_apply_fcurve(nob, fcu, 0, 1); + posttrans_fcurve_clean(fcu); + ANIM_nla_mapping_apply_fcurve(nob, fcu, 1, 1); + } + else + posttrans_fcurve_clean(fcu); + } + } + + /* free temp memory */ + BLI_freelistN(&anim_data); + } + + /* make sure all F-Curves are set correctly */ + ANIM_editkeyframes_refresh(&ac); + } else if (t->obedit) { // TRANSFORM_FIX_ME // if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) @@ -4260,26 +4876,6 @@ void special_aftertrans_update(TransInfo *t) posttrans_nla_clean(t); } } - else if (t->spacetype == SPACE_IPO) { - // FIXME! is there any code from the old transform_ipo that needs to be added back? - - /* after transform, remove duplicate keyframes on a frame that resulted from transform */ - if (G.sipo->ipo) - { - if ( (G.sipo->flag & SIPO_NOTRANSKEYCULL)==0 && - (cancelled == 0) ) - { - /* NOTE: no need to do NLA scaling stuff here, as when there is NLA scaling, - * the transformed handles will get moved wrong (seem to match wrong repeat cycle) - */ - posttrans_ipo_clean(G.sipo->ipo); - } - } - - /* resetting slow-parents isn't really necessary when editing sequence ipo's */ - if (G.sipo->blocktype==ID_SEQ) - resetslowpar= 0; - } else if ((t->flag & T_POSE) && (t->poseobj)) { bArmature *arm; bPose *pose; @@ -4593,7 +5189,7 @@ void createTransData(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_IPO) { t->flag |= T_POINTS|T_2D_EDIT; - createTransIpoData(C, t); + createTransGraphEditData(C, t); #if 0 if (t->data && (t->flag & T_PROP_EDIT)) { sort_trans_data(t); // makes selected become first in array |