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)
This commit is contained in:
2009-03-15 10:39:02 +00:00
parent 6508ad460f
commit 329aa658c9
10 changed files with 489 additions and 274 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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", "");
}
/* ************************************************************************** */

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;