diff options
author | Joshua Leung <aligorith@gmail.com> | 2009-03-15 13:39:02 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2009-03-15 13:39:02 +0300 |
commit | 329aa658c97470a6ac2861c0c9b8108ff0c48182 (patch) | |
tree | 7ed0dac0fb21860dfaab04c4c5269ed6057249eb /source/blender | |
parent | 6508ad460fa91d605de2f62320711b19a319e2cb (diff) |
F-Curve Modifiers: Groundwork for getting these working
- Completed cleaning up the drawing code so that F-Curves with modifiers now get drawn to reflect this.
- Added a temporary operator to add modifiers (hotkey Ctrl-Shift-M)
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_fcurve.h | 28 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 40 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 22 | ||||
-rw-r--r-- | source/blender/editors/include/ED_anim_api.h | 13 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_buttons.c | 81 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_draw.c | 431 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 120 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_intern.h | 10 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_ops.c | 9 | ||||
-rw-r--r-- | source/blender/editors/space_graph/space_graph.c | 9 |
10 files changed, 489 insertions, 274 deletions
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index a8b1ad49648..23c4579de14 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -44,6 +44,8 @@ typedef struct FModifierTypeInfo { /* admin/ident */ short type; /* FMODIFIER_TYPE_### */ short size; /* size in bytes of the struct */ + short acttype; /* eFMI_Action_Types */ + short requires; /* eFMI_Requirement_Flags */ char name[32]; /* name of modifier in interface */ char structName[32]; /* name of struct for SDNA */ @@ -60,13 +62,37 @@ typedef struct FModifierTypeInfo { void (*evaluate_modifier)(struct FCurve *fcu, struct FModifier *fcm, float *cvalue, float evaltime); } FModifierTypeInfo; +/* Values which describe the behaviour of a FModifier Type */ +enum { + /* modifier only modifies values outside of data range */ + FMI_TYPE_EXTRAPOLATION = 0, + /* modifier leaves data-points alone, but adjusts the interpolation between and around them */ + FMI_TYPE_INTERPOLATION, + /* modifier only modifies the values of points (but times stay the same) */ + FMI_TYPE_REPLACE_VALUES, + /* modifier generates a curve regardless of what came before */ + FMI_TYPE_GENERATE_CURVE, +} eFMI_Action_Types; + +/* Flags for the requirements of a FModifier Type */ +enum { + /* modifier requires original data-points (kindof beats the purpose of a modifier stack?) */ + FMI_REQUIRES_ORIGINAL_DATA = (1<<0), + /* modifier doesn't require on any preceeding data (i.e. it will generate a curve). + * Use in conjunction with FMI_TYPE_GENRATE_CURVE + */ + FMI_REQUIRES_NOTHING = (1<<1), + /* refer to modifier instance */ + FMI_REQUIRES_RUNTIME_CHECK = (1<<2), +} eFMI_Requirement_Flags; + /* Function Prototypes for FModifierTypeInfo's */ FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm); FModifierTypeInfo *get_fmodifier_typeinfo(int type); /* ---------------------- */ -// TODO... general API here.. +struct FModifier *fcurve_active_modifier(struct FCurve *fcu); struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type); void fcurve_copy_modifiers(ListBase *dst, ListBase *src); void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 6f3cad7995c..e73a2e158ad 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1105,6 +1105,8 @@ static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime) static FModifierTypeInfo FMI_MODNAME = { FMODIFIER_TYPE_MODNAME, /* type */ sizeof(FMod_ModName), /* size */ + FMI_TYPE_SOME_ACTION, /* action type */ + FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */ "Modifier Name", /* name */ "FMod_ModName", /* struct name */ fcm_modname_free, /* free data */ @@ -1155,6 +1157,7 @@ static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, /* behaviour depends on mode (NOTE: we don't need to do anything...) */ switch (data->mode) { + // TODO: implement factorised polynomial too case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ { /* we overwrite cvalue with the sum of the polynomial */ @@ -1184,6 +1187,8 @@ static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, static FModifierTypeInfo FMI_GENERATOR = { FMODIFIER_TYPE_GENERATOR, /* type */ sizeof(FMod_Generator), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ + FMI_REQUIRES_NOTHING, /* requirements */ "Generator", /* name */ "FMod_Generator", /* struct name */ fcm_generator_free, /* free data */ @@ -1266,6 +1271,8 @@ static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, f static FModifierTypeInfo FMI_ENVELOPE = { FMODIFIER_TYPE_ENVELOPE, /* type */ sizeof(FMod_Envelope), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ "Envelope", /* name */ "FMod_Envelope", /* struct name */ fcm_envelope_free, /* free data */ @@ -1399,6 +1406,8 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo static FModifierTypeInfo FMI_CYCLES = { FMODIFIER_TYPE_CYCLES, /* type */ sizeof(FMod_Cycles), /* size */ + FMI_TYPE_EXTRAPOLATION, /* action type */ + FMI_REQUIRES_ORIGINAL_DATA, /* requirements */ "Cycles", /* name */ "FMod_Cycles", /* struct name */ NULL, /* free data */ @@ -1413,6 +1422,8 @@ static FModifierTypeInfo FMI_CYCLES = { static FModifierTypeInfo FMI_NOISE = { FMODIFIER_TYPE_NOISE, /* type */ sizeof(FMod_Noise), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ "Noise", /* name */ "FMod_Noise", /* struct name */ NULL, /* free data */ @@ -1428,6 +1439,8 @@ static FModifierTypeInfo FMI_NOISE = { static FModifierTypeInfo FMI_FILTER = { FMODIFIER_TYPE_FILTER, /* type */ sizeof(FMod_Filter), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ "Filter", /* name */ "FMod_Filter", /* struct name */ NULL, /* free data */ @@ -1480,6 +1493,8 @@ static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo static FModifierTypeInfo FMI_PYTHON = { FMODIFIER_TYPE_PYTHON, /* type */ sizeof(FMod_Python), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ + FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ "Python", /* name */ "FMod_Python", /* struct name */ fcm_python_free, /* free data */ @@ -1499,7 +1514,8 @@ static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES]; static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */ /* This function only gets called when FMI_INIT is non-zero */ -static void fmods_init_typeinfo () { +static void fmods_init_typeinfo () +{ fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */ fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */ fmodifiersTypeInfo[2]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */ @@ -1568,6 +1584,8 @@ FModifier *fcurve_add_modifier (FCurve *fcu, int type) /* add modifier itself */ fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); + fcm->type = type; + fcm->flag = FMODIFIER_FLAG_EXPANDED; BLI_addtail(&fcu->modifiers, fcm); /* add modifier's data */ @@ -1674,12 +1692,30 @@ void fcurve_bake_modifiers (FCurve *fcu, int start, int end) fcu->driver= driver; } +/* Find the active F-Curve Modifier */ +FModifier *fcurve_active_modifier (FCurve *fcu) +{ + FModifier *fcm; + + /* sanity checks */ + if ELEM(NULL, fcu, fcu->modifiers.first) + return NULL; + + /* loop over modifiers until 'active' one is found */ + for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) { + if (fcm->flag & FMODIFIER_FLAG_ACTIVE) + return fcm; + } + + /* no modifier is active */ + return NULL; +} + /* ***************************** F-Curve - Evaluation ********************************* */ /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") * Note: this is also used for drivers */ -// TODO: set up the modifier system... float evaluate_fcurve (FCurve *fcu, float evaltime) { FModifier *fcm; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 689520eb0fa..ea30fe83f35 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -310,6 +310,12 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* quick macro to test if AnimData is usable for drivers */ #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first) +/* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ +#define ANIMCHANNEL_SELOK(test_func) \ + ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \ + ((filter_mode & ANIMFILTER_SEL) && test_func) || \ + ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) + /* ----------- 'Private' Stuff --------------- */ /* this function allocates memory for a new bAnimListElem struct for the @@ -509,8 +515,8 @@ static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionG if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { /* only work with this channel and its subchannels if it is editable */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) { - /* only include this curve if selected */ - if (!(filter_mode & ANIMFILTER_SEL) || (SEL_FCU(fcu))) { + /* only include this curve if selected in a way consistent with the filtering requirements */ + if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) ) { /* only include if this curve is active */ if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) { /* owner/ownertype will be either object or action-channel, depending if it was dopesheet or part of an action */ @@ -543,7 +549,7 @@ static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter /* add this group as a channel first */ if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) { /* check if filtering by selection */ - if ( !(filter_mode & ANIMFILTER_SEL) || SEL_AGRP(agrp) ) { + if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) { ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id); if (ale) { BLI_addtail(anim_data, ale); @@ -569,8 +575,7 @@ static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter * - we're interested in keyframes, but not if they appear in selected channels */ if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || - ( (!(filter_mode & ANIMFILTER_SEL) || (SEL_AGRP(agrp))) && - (filter_mode & ANIMFILTER_CURVESONLY) ) ) + ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) && (filter_mode & ANIMFILTER_CURVESONLY) ) ) { if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { // XXX the 'owner' info here needs review... @@ -709,7 +714,7 @@ static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter /* loop over layers as the conditions are acceptable */ for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { /* only if selected */ - if (!(filter_mode & ANIMFILTER_SEL) || SEL_GPL(gpl)) { + if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) { /* only if editable */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { /* add to list */ @@ -784,7 +789,6 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* add material's F-Curve channels? */ if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) { - //items += animdata_filter_ipocurves(anim_data, ma->ipo, filter_mode, base, ANIMTYPE_OBJECT, (ID *)ma); // XXX the 'owner' info here is still subject to improvement items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma); } @@ -873,7 +877,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B /* add this object as a channel first */ if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { /* check if filtering by selection */ - if ( !(filter_mode & ANIMFILTER_SEL) || ((base->flag & SELECT) || (base == sce->basact)) ) { + if (ANIMCHANNEL_SELOK( ((base->flag & SELECT) || (base == sce->basact)) )) { ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL); if (ale) { BLI_addtail(anim_data, ale); @@ -1041,7 +1045,7 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */ if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { /* check if filtering by selection */ - if ( !(filter_mode & ANIMFILTER_SEL) || (sce->flag & SCE_DS_SELECTED) ) { + if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) { ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL); if (ale) { BLI_addtail(anim_data, ale); diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 08c5f752fd1..0210e3d6a85 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -149,12 +149,13 @@ typedef enum eAnim_KeyType { typedef enum eAnimFilter_Flags { ANIMFILTER_VISIBLE = (1<<0), /* should channels be visible (in terms of hierarchy only) */ ANIMFILTER_SEL = (1<<1), /* should channels be selected */ - ANIMFILTER_FOREDIT = (1<<2), /* does editable status matter */ - ANIMFILTER_CURVESONLY = (1<<3), /* don't include summary-channels, etc. */ - ANIMFILTER_CHANNELS = (1<<4), /* make list for interface drawing */ - ANIMFILTER_ACTGROUPED = (1<<5), /* belongs to the active actiongroup */ - ANIMFILTER_CURVEVISIBLE = (1<<6), /* F-Curve is visible for editing/viewing in Graph Editor */ - ANIMFILTER_ACTIVE = (1<<7), /* channel should be 'active' */ // FIXME: this is only relevant for F-Curves for now + ANIMFILTER_UNSEL = (1<<2), /* should channels be NOT selected */ + ANIMFILTER_FOREDIT = (1<<3), /* does editable status matter */ + ANIMFILTER_CURVESONLY = (1<<4), /* don't include summary-channels, etc. */ + ANIMFILTER_CHANNELS = (1<<5), /* make list for interface drawing */ + ANIMFILTER_ACTGROUPED = (1<<6), /* belongs to the active actiongroup */ + ANIMFILTER_CURVEVISIBLE = (1<<7), /* F-Curve is visible for editing/viewing in Graph Editor */ + ANIMFILTER_ACTIVE = (1<<8), /* channel should be 'active' */ // FIXME: this is only relevant for F-Curves for now } eAnimFilter_Flags; diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 859aab9283e..7c078ad184d 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -52,6 +52,7 @@ #include "BKE_curve.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" +#include "BKE_fcurve.h" #include "BKE_object.h" #include "BKE_global.h" #include "BKE_scene.h" @@ -218,32 +219,92 @@ static void graph_panel_drivers(const bContext *C, ARegion *ar, short cntrl, bAn /* -------------- */ +#define B_FMODIFIER_REDRAW 20 + static void do_graph_region_modifier_buttons(bContext *C, void *arg, int event) { - //Scene *scene= CTX_data_scene(C); - switch(event) { + case B_REDR: + case B_FMODIFIER_REDRAW: + ED_area_tag_redraw(CTX_wm_area(C)); + return; /* no notifier! */ + } +} + +/* for now, just print name of modifier */ +static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco) +{ + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + uiBut *but; + short active= (fcm->flag & FMODIFIER_FLAG_ACTIVE); + short width= 314; + short height = 0; + int rb_col; + + /* draw header */ + { + uiBlockSetEmboss(block, UI_EMBOSSN); + + /* rounded header */ + if (active) uiBlockSetCol(block, TH_BUT_ACTION); + rb_col= (active)?-20:20; + uiDefBut(block, ROUNDBOX, B_REDR, "", 10-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15.0, (float)(rb_col-20), ""); + if (active) uiBlockSetCol(block, TH_AUTO); + + /* expand */ + uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT, 10-7, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded"); + + /* name */ + if (fmi) + uiDefBut(block, LABEL, 1, fmi->name, 10+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type"); + else + uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 10+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type"); + + /* delete button */ + but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 10+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete layer"); + //uiButSetFunc(but, gp_ui_dellayer_cb, gpd, NULL); + uiBlockSetEmboss(block, UI_EMBOSS); } - /* default for now */ - //WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); + /* when modifier is expanded, draw settings */ + if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { + height= 97; + + /* draw backdrop */ + if (active) uiBlockSetCol(block, TH_BUT_ACTION); + uiDefBut(block, ROUNDBOX, B_REDR, "", 10-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); + if (active) uiBlockSetCol(block, TH_AUTO); + } + + /* adjust height for new to start */ + (*yco) -= (height + 27); } static void graph_panel_modifiers(const bContext *C, ARegion *ar, short cntrl, bAnimListElem *ale) { - //FCurve *fcu= (FCurve *)ale->data; - //FModifier *fcm; + FCurve *fcu= (FCurve *)ale->data; + FModifier *fcm; uiBlock *block; + int yco= 190; block= uiBeginBlock(C, ar, "graph_panel_modifiers", UI_EMBOSS, UI_HELV); if (uiNewPanel(C, ar, block, "Modifiers", "Graph", 340, 30, 318, 254)==0) return; uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL); - - /* to force height */ - uiNewPanelHeight(block, 204); // XXX variable height! + /* 'add modifier' button at top of panel */ + // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator + uiDefButO(block, BUT, "GRAPHEDIT_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 225, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve"); + + /* draw each modifier */ + for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) + graph_panel_modifier_draw(block, fcu, fcm, &yco); + /* since these buttons can have variable height */ + if (yco < 0) + uiNewPanelHeight(block, (204 - yco)); + else + uiNewPanelHeight(block, 204); } /* -------------- */ @@ -253,7 +314,7 @@ static void graph_panel_modifiers(const bContext *C, ARegion *ar, short cntrl, b * when the caller is done with it. */ // TODO: move this to anim api with another name? -static bAnimListElem *get_active_fcurve_channel (bAnimContext *ac) +bAnimListElem *get_active_fcurve_channel (bAnimContext *ac) { ListBase anim_data = {NULL, NULL}; int filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE | ANIMFILTER_CURVESONLY); diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 1efa257c317..bd57e9750eb 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <math.h> #include <string.h> +#include <float.h> #ifdef HAVE_CONFIG_H #include <config.h> @@ -401,9 +402,62 @@ static void draw_fcurve_samples (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* Curve ---------------- */ +/* minimum pixels per gridstep + * XXX: defined in view2d.c - must keep these in sync or relocate to View2D header! + */ +#define MINGRIDSTEP 35 + +/* helper func - just draw the F-Curve by sampling the visible region (for drawing curves with modifiers) */ +static void draw_fcurve_curve (FCurve *fcu, SpaceIpo *sipo, View2D *v2d, View2DGrid *grid) +{ + ChannelDriver *driver; + float samplefreq, ctime; + float stime, etime; + + /* disable any drivers temporarily */ + driver= fcu->driver; + fcu->driver= NULL; + + + /* Note about sampling frequency: + * Ideally, this is chosen such that we have 1-2 pixels = 1 segment + * which means that our curves can be as smooth as possible. However, + * this does mean that curves may not be fully accurate (i.e. if they have + * sudden spikes which happen at the sampling point, we may have problems). + * Also, this may introduce lower performance on less densely detailed curves,' + * though it is impossible to predict this from the modifiers! + * + * If the automatically determined sampling frequency is likely to cause an infinite + * loop (i.e. too close to FLT_EPSILON), fall back to default of 0.001 + */ + /* grid->dx is the first float in View2DGrid struct, so just cast to float pointer, and use it + * It represents the number of 'frames' between gridlines, but we divide by MINGRIDSTEP to get pixels-steps + */ + // TODO: perhaps we should have 1.0 frames as upper limit so that curves don't get too distorted? + samplefreq= *((float *)grid) / MINGRIDSTEP; + if (IS_EQ(samplefreq, 0)) samplefreq= 0.001f; + + + /* the start/end times are simply the horizontal extents of the 'cur' rect */ + stime= v2d->cur.xmin; + etime= v2d->cur.xmax; + + + /* at each sampling interval, add a new vertex */ + glBegin(GL_LINE_STRIP); + + for (ctime= stime; ctime <= etime; ctime += samplefreq) + glVertex2f( ctime, evaluate_fcurve(fcu, ctime) ); + + glEnd(); + + /* restore driver */ + fcu->driver= driver; +} + /* helper func - draw a samples-based F-Curve */ // TODO: add offset stuff... -static void draw_fcurve_repeat_samples (FCurve *fcu, View2D *v2d) +static void draw_fcurve_curve_samples (FCurve *fcu, View2D *v2d) { FPoint *prevfpt= fcu->fpt; FPoint *fpt= prevfpt + 1; @@ -412,26 +466,23 @@ static void draw_fcurve_repeat_samples (FCurve *fcu, View2D *v2d) glBegin(GL_LINE_STRIP); - /* extrapolate to left? */ - if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) { - /* left-side of view comes before first keyframe, so need to extend as not cyclic */ - if (prevfpt->vec[0] > v2d->cur.xmin) { - v[0]= v2d->cur.xmin; - - /* y-value depends on the interpolation */ - if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) { - /* just extend across the first keyframe's value */ - v[1]= prevfpt->vec[1]; - } - else { - /* extrapolate linear dosnt use the handle, use the next points center instead */ - fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]); - if (fac) fac= 1.0f/fac; - v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]); - } - - glVertex2fv(v); + /* extrapolate to left? - left-side of view comes before first keyframe? */ + if (prevfpt->vec[0] > v2d->cur.xmin) { + v[0]= v2d->cur.xmin; + + /* y-value depends on the interpolation */ + if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) { + /* just extend across the first keyframe's value */ + v[1]= prevfpt->vec[1]; + } + else { + /* extrapolate linear dosnt use the handle, use the next points center instead */ + fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]); + if (fac) fac= 1.0f/fac; + v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]); } + + glVertex2fv(v); } /* if only one sample, add it now */ @@ -440,7 +491,6 @@ static void draw_fcurve_repeat_samples (FCurve *fcu, View2D *v2d) /* loop over samples, drawing segments */ /* draw curve between first and last keyframe (if there are enough to do so) */ - // XXX this doesn't take into account modifiers, or sample data while (b--) { /* Linear interpolation: just add one point (which should add a new line segment) */ glVertex2fv(prevfpt->vec); @@ -455,95 +505,90 @@ static void draw_fcurve_repeat_samples (FCurve *fcu, View2D *v2d) } /* extrapolate to right? (see code for left-extrapolation above too) */ - if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) { - if (prevfpt->vec[0] < v2d->cur.xmax) { - v[0]= v2d->cur.xmax; - - /* y-value depends on the interpolation */ - if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) { - /* based on last keyframe's value */ - v[1]= prevfpt->vec[1]; - } - else { - /* extrapolate linear dosnt use the handle, use the previous points center instead */ - fpt = prevfpt-1; - fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]); - if (fac) fac= 1.0f/fac; - v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]); - } - - glVertex2fv(v); + if (prevfpt->vec[0] < v2d->cur.xmax) { + v[0]= v2d->cur.xmax; + + /* y-value depends on the interpolation */ + if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) { + /* based on last keyframe's value */ + v[1]= prevfpt->vec[1]; + } + else { + /* extrapolate linear dosnt use the handle, use the previous points center instead */ + fpt = prevfpt-1; + fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]); + if (fac) fac= 1.0f/fac; + v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]); } + + glVertex2fv(v); } glEnd(); } /* helper func - draw one repeat of an F-Curve */ -static void draw_fcurve_repeat (FCurve *fcu, View2D *v2d, float cycxofs, float cycyofs, float *facp) +static void draw_fcurve_curve_bezts (FCurve *fcu, View2D *v2d, View2DGrid *grid) { BezTriple *prevbezt= fcu->bezt; BezTriple *bezt= prevbezt+1; float v1[2], v2[2], v3[2], v4[2]; float *fp, data[120]; - float fac= *(facp); + float fac= 0.0f; int b= fcu->totvert-1; int resol; glBegin(GL_LINE_STRIP); /* extrapolate to left? */ - if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) { + if (prevbezt->vec[1][0] > v2d->cur.xmin) { /* left-side of view comes before first keyframe, so need to extend as not cyclic */ - if (prevbezt->vec[1][0] > v2d->cur.xmin) { - v1[0]= v2d->cur.xmin; - - /* y-value depends on the interpolation */ - if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) { - /* just extend across the first keyframe's value */ - v1[1]= prevbezt->vec[1][1]; - } - else if (prevbezt->ipo==BEZT_IPO_LIN) { - /* extrapolate linear dosnt use the handle, use the next points center instead */ - fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); - if (fac) fac= 1.0f/fac; - v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]); - } - else { - /* based on angle of handle 1 (relative to keyframe) */ - fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); - if (fac) fac= 1.0f/fac; - v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]); - } - - glVertex2fv(v1); + v1[0]= v2d->cur.xmin; + + /* y-value depends on the interpolation */ + if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) { + /* just extend across the first keyframe's value */ + v1[1]= prevbezt->vec[1][1]; + } + else if (prevbezt->ipo==BEZT_IPO_LIN) { + /* extrapolate linear dosnt use the handle, use the next points center instead */ + fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); + if (fac) fac= 1.0f/fac; + v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]); + } + else { + /* based on angle of handle 1 (relative to keyframe) */ + fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); + if (fac) fac= 1.0f/fac; + v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]); } + + glVertex2fv(v1); } /* if only one keyframe, add it now */ if (fcu->totvert == 1) { - v1[0]= prevbezt->vec[1][0] + cycxofs; - v1[1]= prevbezt->vec[1][1] + cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); } /* draw curve between first and last keyframe (if there are enough to do so) */ - // XXX this doesn't take into account modifiers, or sample data while (b--) { if ((fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST)) { /* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */ - v1[0]= prevbezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); - v1[0]= bezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; + v1[0]= bezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); } else if (prevbezt->ipo==BEZT_IPO_LIN) { /* Linear interpolation: just add one point (which should add a new line segment) */ - v1[0]= prevbezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); } else { @@ -560,23 +605,23 @@ static void draw_fcurve_repeat (FCurve *fcu, View2D *v2d, float cycxofs, float c if (resol < 2) { /* only draw one */ - v1[0]= prevbezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); } else { /* clamp resolution to max of 32 */ if (resol > 32) resol= 32; - v1[0]= prevbezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; - v2[0]= prevbezt->vec[2][0]+cycxofs; - v2[1]= prevbezt->vec[2][1]+cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; + v2[0]= prevbezt->vec[2][0]; + v2[1]= prevbezt->vec[2][1]; - v3[0]= bezt->vec[0][0]+cycxofs; - v3[1]= bezt->vec[0][1]+cycyofs; - v4[0]= bezt->vec[1][0]+cycxofs; - v4[1]= bezt->vec[1][1]+cycyofs; + v3[0]= bezt->vec[0][0]; + v3[1]= bezt->vec[0][1]; + v4[0]= bezt->vec[1][0]; + v4[1]= bezt->vec[1][1]; correct_bezpart(v1, v2, v3, v4); @@ -594,152 +639,41 @@ static void draw_fcurve_repeat (FCurve *fcu, View2D *v2d, float cycxofs, float c /* last point? */ if (b == 0) { - v1[0]= prevbezt->vec[1][0]+cycxofs; - v1[1]= prevbezt->vec[1][1]+cycyofs; + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; glVertex2fv(v1); } } /* extrapolate to right? (see code for left-extrapolation above too) */ - if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) { - if (prevbezt->vec[1][0] < v2d->cur.xmax) { - v1[0]= v2d->cur.xmax; - - /* y-value depends on the interpolation */ - if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) { - /* based on last keyframe's value */ - v1[1]= prevbezt->vec[1][1]; - } - else if (prevbezt->ipo==BEZT_IPO_LIN) { - /* extrapolate linear dosnt use the handle, use the previous points center instead */ - bezt = prevbezt-1; - fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); - if (fac) fac= 1.0f/fac; - v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]); - } - else { - /* based on angle of handle 1 (relative to keyframe) */ - fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); - if (fac) fac= 1.0f/fac; - v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]); - } - - glVertex2fv(v1); + if (prevbezt->vec[1][0] < v2d->cur.xmax) { + v1[0]= v2d->cur.xmax; + + /* y-value depends on the interpolation */ + if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) { + /* based on last keyframe's value */ + v1[1]= prevbezt->vec[1][1]; + } + else if (prevbezt->ipo==BEZT_IPO_LIN) { + /* extrapolate linear dosnt use the handle, use the previous points center instead */ + bezt = prevbezt-1; + fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); + if (fac) fac= 1.0f/fac; + v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]); + } + else { + /* based on angle of handle 1 (relative to keyframe) */ + fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]); + if (fac) fac= 1.0f/fac; + v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]); } + + glVertex2fv(v1); } glEnd(); - - /* return fac, as we alter it */ - *(facp) = fac; } -#if 0 // XXX old animation system unconverted code! - -/* draw all ipo-curves */ -static void draw_ipocurves(SpaceIpo *sipo, ARegion *ar, int sel) -{ - View2D *v2d= &ar->v2d; - EditIpo *ei; - int nr, val/*, pickselcode=0*/; - - /* if we're drawing for GL_SELECT, reset pickselcode first - * - there's only one place that will do this, so it should be fine - */ - //if (G.f & G_PICKSEL) - // pickselcode= 1; - - ei= sipo->editipo; - for (nr=0; nr<sipo->totipo; nr++, ei++) { - if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) { - /* val is used to indicate if curve can be edited */ - //if (G.f & G_PICKSEL) { - // /* when using OpenGL to select stuff (on mouseclick) */ - // glLoadName(pickselcode++); - // val= 1; - //} - //else { - /* filter to only draw those that are selected or unselected (based on drawing mode */ - val= (ei->flag & (IPO_SELECT+IPO_EDIT)) != 0; - val= (val==sel); - //} - - /* only draw those curves that we can draw */ - if (val) { - IpoCurve *icu= ei->icu; - float cycdx=0.0f, cycdy=0.0f, cycxofs=0.0f, cycyofs=0.0f; - const int lastindex= (icu->totvert-1); - float fac= 0.0f; - int cycount=1; - - /* set color for curve curve: - * - bitflag curves (evil) must always be drawn coloured as they cannot work with IPO-Keys - * - when IPO-Keys are shown, individual curves are not editable, so we show by drawing them all black - */ - if ((sipo->showkey) && (ei->disptype!=IPO_DISPBITS)) UI_ThemeColor(TH_TEXT); - else cpack(ei->col); - - /* cyclic curves - get offset and number of repeats to display */ - if (icu->extrap & IPO_CYCL) { - BezTriple *bezt= icu->bezt; - BezTriple *lastbezt= bezt + lastindex; - - /* calculate cycle length and amplitude */ - cycdx= lastbezt->vec[1][0] - bezt->vec[1][0]; - cycdy= lastbezt->vec[1][1] - bezt->vec[1][1]; - - /* check that the cycle does have some length */ - if (cycdx > 0.01f) { - /* count cycles before first frame */ - while (icu->bezt->vec[1][0]+cycxofs > v2d->cur.xmin) { - cycxofs -= cycdx; - if (icu->extrap & IPO_DIR) cycyofs-= cycdy; - cycount++; - } - - /* count cycles after last frame (and adjust offset) */ - fac= 0.0f; - while (lastbezt->vec[1][0]+fac < v2d->cur.xmax) { - cycount++; - fac += cycdx; - } - } - } - - /* repeat process for each repeat */ - while (cycount--) { - /* bitflag curves are drawn differently to normal curves */ - if (ei->disptype==IPO_DISPBITS) - draw_ipocurve_repeat_bits(icu, v2d, cycxofs); - else - draw_ipocurve_repeat_normal(icu, v2d, cycxofs, cycyofs, &fac); - - /* prepare for next cycle by adjusing offsets */ - cycxofs += cycdx; - if (icu->extrap & IPO_DIR) cycyofs += cycdy; - } - - /* vertical line that indicates the end of a speed curve */ - if ((sipo->blocktype==ID_CU) && (icu->adrcode==CU_SPEED)) { - int b= icu->totvert-1; - - if (b) { - BezTriple *bezt= icu->bezt+b; - - glColor3ub(0, 0, 0); - - glBegin(GL_LINES); - glVertex2f(bezt->vec[1][0], 0.0f); - glVertex2f(bezt->vec[1][0], bezt->vec[1][1]); - glEnd(); - } - } - } - } - } -} -#endif // XXX old animation system unconverted code - #if 0 static void draw_ipokey(SpaceIpo *sipo, ARegion *ar) { @@ -758,7 +692,9 @@ static void draw_ipokey(SpaceIpo *sipo, ARegion *ar) } #endif -void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) +/* Public Curve-Drawing API ---------------- */ + +void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid *grid) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -774,20 +710,22 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) */ for (ale=anim_data.first; ale; ale=ale->next) { FCurve *fcu= (FCurve *)ale->key_data; - Object *nob= ANIM_nla_mapping_get(ac, ale); - float fac=0.0f; // dummy var + //FModifier *fcm= fcurve_active_modifier(fcu); + //Object *nob= ANIM_nla_mapping_get(ac, ale); /* map keyframes for drawing if scaled F-Curve */ - if (nob) - ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0); + //if (nob) + // ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0); - /* draw curve - if there's an active modifier (or a stack of modifiers) drawing these takes presidence, - * unless modifiers in use will not alter any of the values within the keyframed area... + /* draw curve: + * - curve line may be result of one or more destructive modifiers or just the raw data, + * so we need to check which method should be used + * - controls from active modifier take precidence over keyframes + * (XXX! editing tools need to take this into account!) */ - - - /* draw curve - as defined by keyframes */ - if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { + + /* 1) draw curve line */ + { /* set color/drawing style for curve itself */ if ( ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || (fcu->flag & FCURVE_PROTECTED) ) { /* protected curves (non editable) are drawn with dotted lines */ @@ -803,18 +741,35 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) glColor3fv(fcu->color); } + /* anti-aliased lines for less jagged appearance */ + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + /* draw F-Curve */ - if (fcu->bezt) - draw_fcurve_repeat(fcu, &ar->v2d, 0, 0, &fac); // XXX this call still needs a lot more work - else if (fcu->fpt) - draw_fcurve_repeat_samples(fcu, &ar->v2d); - /*else modifiers? */ + if (fcu->modifiers.first) { + /* draw a curve affected by modifiers by sampling its points */ + draw_fcurve_curve(fcu, sipo, &ar->v2d, grid); + } + else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { + /* just draw curve based on defined data (i.e. no modifiers) */ + if (fcu->bezt) + draw_fcurve_curve_bezts(fcu, &ar->v2d, grid); + else if (fcu->fpt) + draw_fcurve_curve_samples(fcu, &ar->v2d); + } /* restore settings */ setlinestyle(0); - - /* draw handles and vertices as appropriate */ + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + } + + /* 2) draw handles and vertices as appropriate based on active */ + if ((fcu->modifiers.first) && (fcm) && (fcm->type != FMODIFIER_TYPE_CYCLES)) { + // TODO: need to add code to show these... for cycles modifier, should fall through though... + } + else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { if (fcu->bezt) { /* only draw handles/vertices on keyframes */ draw_fcurve_handles(sipo, ar, fcu); @@ -827,8 +782,8 @@ 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, 0); + //if (nob) + // ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 0); } /* free list of curves */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index d98ed38da9c..43a3b3628ad 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1018,12 +1018,25 @@ void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot) * of values to -180 degrees to 180 degrees. */ +#if 0 // XXX this is not ready for the primetime yet + +/* set of three euler-rotation F-Curves */ +typedef struct tEulerFilter { + ID *id; /* ID-block which owns the channels */ + FCurve *fcu1, *fcu2, *fcu3; /* x,y,z rotation curves */ + int i1, i2, i3; /* current index for each curve */ +} tEulerFilter; + static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) { bAnimContext ac; - //ListBase anim_data= {NULL, NULL}; - //bAnimListElem *ale; - //int filter; + + ListBase anim_data= {NULL, NULL}; + bAnimListElem *ale; + int filter; + + ListBase eulers = {NULL, NULL}; + tEulerFilter *euf= NULL; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -1035,7 +1048,33 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) * 2) Each set of three F-Curves is processed for each keyframe, with the values being * processed according to one of several ways. */ + + /* step 1: extract only the rotation f-curves */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + for (ale= anim_data.first; ale; ale= ale->next) { + FCurve *fcu = (FCurve *)ale->data; + + /* check if this is an appropriate F-Curve + * - only rotation curves + * - for pchan curves, make sure we're only using the euler curves + */ + if (ELEM(0, fcu->rna_path, strstr(fcu->rna_path, "rotation"))) + continue; + if (strstr(fcu->rna_path, "pose.pose_channels")) { + if (strstr(fcu->rna_path, "euler_rotation") == 0) + continue; + } + + /* check if current set of 3-curves is suitable to add this curve to + * - things like whether the current set of curves is 'full' should be checked later only + * - first check if id-blocks are compatible + */ + if ((euf) && (ale->id != euf->id)) { + + } + } // XXX for now return OPERATOR_CANCELLED; @@ -1055,6 +1094,8 @@ void GRAPHEDIT_OT_keyframes_euler_filter (wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +#endif // XXX this is not ready for the primetime yet + /* ***************** Snap Current Frame Operator *********************** */ /* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */ @@ -1376,3 +1417,76 @@ void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot) } /* ************************************************************************** */ +/* F-CURVE MODIFIERS */ + +/* ******************** Add F-Curve Modifier Operator *********************** */ + +/* F-Modifier types - duplicate of existing codes... */ + // XXX how can we have this list from the RNA definitions instead? +EnumPropertyItem prop_fmodifier_types[] = { + {FMODIFIER_TYPE_GENERATOR, "GENERATOR", "Generator", ""}, + {FMODIFIER_TYPE_ENVELOPE, "ENVELOPE", "Envelope", ""}, + {FMODIFIER_TYPE_CYCLES, "CYCLES", "Cycles", ""}, + {FMODIFIER_TYPE_NOISE, "NOISE", "Noise", ""}, + {FMODIFIER_TYPE_FILTER, "FILTER", "Filter", ""}, + {FMODIFIER_TYPE_PYTHON, "PYTHON", "Python", ""}, + {0, NULL, NULL, NULL} +}; + +static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + bAnimListElem *ale; + FCurve *fcu; + short type; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + // xxx call the raw methods here instead? + ale= get_active_fcurve_channel(&ac); + if (ale == NULL) + return OPERATOR_CANCELLED; + + fcu= (FCurve *)ale->data; + MEM_freeN(ale); + if (fcu == NULL) + return OPERATOR_CANCELLED; + + + /* get type of modifier to add */ + type= RNA_enum_get(op->ptr, "type"); + + /* add F-Modifier of specified type to active F-Curve */ + fcurve_add_modifier(fcu, type); + + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_fmodifier_add (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add F-Curve Modifier"; + ot->idname= "GRAPHEDIT_OT_fmodifier_add"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graph_fmodifier_add_exec; + ot->poll= ED_operator_areaactive; // XXX need active F-Curve + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_fmodifier_types, 0, "Type", ""); +} + +/* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 6144556378a..ab915a97232 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -31,9 +31,11 @@ struct bContext; struct wmWindowManager; struct bAnimContext; +struct bAnimListElem; struct SpaceIpo; struct ScrArea; struct ARegion; +struct View2DGrid; /* internal exports only */ @@ -44,7 +46,7 @@ struct ARegion *graph_has_buttons_region(struct ScrArea *sa); /* ***************************************** */ /* graph_draw.c */ void graph_draw_channel_names(struct bAnimContext *ac, struct SpaceIpo *sipo, struct ARegion *ar); -void graph_draw_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, struct ARegion *ar); +void graph_draw_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, struct ARegion *ar, struct View2DGrid *grid); /* ***************************************** */ /* graph_header.c */ @@ -119,11 +121,17 @@ enum { GRAPHKEYS_MIRROR_MARKER, } eGraphKeys_Mirror_Mode; +/* ----------- */ + +void GRAPHEDIT_OT_fmodifier_add(struct wmOperatorType *ot); + /* ***************************************** */ /* graph_buttons.c */ void GRAPHEDIT_OT_properties(struct wmOperatorType *ot); void graph_region_buttons(const struct bContext *C, struct ARegion *ar); +struct bAnimListElem *get_active_fcurve_channel(struct bAnimContext *ac); + /* ***************************************** */ /* graph_ops.c */ void graphedit_keymap(struct wmWindowManager *wm); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 80b8dcbf0ff..91cc7557476 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -126,6 +126,10 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPHEDIT_OT_keyframes_paste); //TODO: insertkey... + + /* F-Curve Modifiers */ + // XXX temporary? + WM_operatortype_append(GRAPHEDIT_OT_fmodifier_add); } /* ************************** registration - keymaps **********************************/ @@ -195,6 +199,11 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) WM_keymap_add_item(keymap, "GRAPHEDIT_OT_set_previewrange", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); WM_keymap_add_item(keymap, "GRAPHEDIT_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); + /* F-Curve Modifiers */ + // XXX these are temporary? operators... + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + + /* transform system */ transform_keymap_for_space(wm, keymap, SPACE_IPO); } diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index e6365db92ad..9466a0674d1 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -230,12 +230,13 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar) unitx= (sipo->flag & SIPO_DRAWTIME)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE; grid= UI_view2d_grid_calc(C, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, ar->winx, ar->winy); UI_view2d_grid_draw(C, v2d, grid, V2D_GRIDLINES_ALL); - UI_view2d_grid_free(grid); /* draw data */ - if (ANIM_animdata_get_context(C, &ac)) { - graph_draw_curves(&ac, sipo, ar); - } + if (ANIM_animdata_get_context(C, &ac)) + graph_draw_curves(&ac, sipo, ar, grid); + + /* only free grid after drawing data, as we need to use it to determine sampling rate */ + UI_view2d_grid_free(grid); /* current frame */ if (sipo->flag & SIPO_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS; |