From b77eccf80139ed8de65c205f6f723ae827e82c07 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 31 Jan 2013 08:19:11 +0000 Subject: patch [#33985] Added FModifierEnvelope control_point add remove to API from Peter Staples (batfinger) --- source/blender/blenkernel/BKE_fcurve.h | 3 + source/blender/blenkernel/intern/fmodifier.c | 86 +++++++++++++++++++ source/blender/editors/animation/fmodifier_ui.c | 83 +----------------- source/blender/makesrna/intern/rna_fcurve.c | 107 ++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 82 deletions(-) diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index bf2f1262eee..6ce7b952b97 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -41,6 +41,7 @@ struct FModifier; struct ChannelDriver; struct DriverVar; struct DriverTarget; +struct FCM_EnvelopeData; struct bAction; struct BezTriple; @@ -181,6 +182,8 @@ void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *c void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end); +int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array, float frame, int arraylen, short *exists); + /* ************** F-Curves API ******************** */ /* -------- Data Managemnt -------- */ diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 7b007af86d6..c3fc659137d 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -480,6 +480,92 @@ static FModifierTypeInfo FMI_ENVELOPE = { fcm_envelope_evaluate /* evaluate */ }; +/* exported function for finding points */ + +/* Binary search algorithm for finding where to insert Envelope Data Point. + * Returns the index to insert at (data already at that index will be offset if replace is 0) + */ +#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001f + +int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[], float frame, int arraylen, short *exists) +{ + int start = 0, end = arraylen; + int loopbreaker = 0, maxloop = arraylen * 2; + + /* initialize exists-flag first */ + *exists = 0; + + /* sneaky optimizations (don't go through searching process if...): + * - keyframe to be added is to be added out of current bounds + * - keyframe to be added would replace one of the existing ones on bounds + */ + if ((arraylen <= 0) || (array == NULL)) { + printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array\n"); + return 0; + } + else { + /* check whether to add before/after/on */ + float framenum; + + /* 'First' Point (when only one point, this case is used) */ + framenum = array[0].time; + if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { + *exists = 1; + return 0; + } + else if (frame < framenum) { + return 0; + } + + /* 'Last' Point */ + framenum = array[(arraylen - 1)].time; + if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { + *exists = 1; + return (arraylen - 1); + } + else if (frame > framenum) { + return arraylen; + } + } + + + /* most of the time, this loop is just to find where to put it + * - 'loopbreaker' is just here to prevent infinite loops + */ + for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { + /* compute and get midpoint */ + int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ + float midfra = array[mid].time; + + /* check if exactly equal to midpoint */ + if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) { + *exists = 1; + return mid; + } + + /* repeat in upper/lower half */ + if (frame > midfra) { + start = mid + 1; + } + else if (frame < midfra) { + end = mid - 1; + } + } + + /* print error if loop-limit exceeded */ + if (loopbreaker == (maxloop - 1)) { + printf("Error: binarysearch_fcm_envelopedata_index() was taking too long\n"); + + // include debug info + printf("\tround = %d: start = %d, end = %d, arraylen = %d\n", loopbreaker, start, end, arraylen); + } + + /* not found, so return where to place it */ + return start; +} +#undef BINARYSEARCH_FRAMEEQ_THRESH + + /* Cycles F-Curve Modifier --------------------------- */ /* This modifier changes evaltime to something that exists within the curve's frame-range, diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 6bd774e084a..cc2366affe6 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -327,88 +327,7 @@ static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE); } -/* --------------- */ - -#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001f - -/* Binary search algorithm for finding where to insert Envelope Data Point. - * Returns the index to insert at (data already at that index will be offset if replace is 0) - */ -static int binarysearch_fcm_envelopedata_index(FCM_EnvelopeData array[], float frame, int arraylen, short *exists) -{ - int start = 0, end = arraylen; - int loopbreaker = 0, maxloop = arraylen * 2; - - /* initialize exists-flag first */ - *exists = 0; - - /* sneaky optimizations (don't go through searching process if...): - * - keyframe to be added is to be added out of current bounds - * - keyframe to be added would replace one of the existing ones on bounds - */ - if ((arraylen <= 0) || (array == NULL)) { - printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array\n"); - return 0; - } - else { - /* check whether to add before/after/on */ - float framenum; - - /* 'First' Point (when only one point, this case is used) */ - framenum = array[0].time; - if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists = 1; - return 0; - } - else if (frame < framenum) - return 0; - - /* 'Last' Point */ - framenum = array[(arraylen - 1)].time; - if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists = 1; - return (arraylen - 1); - } - else if (frame > framenum) - return arraylen; - } - - - /* most of the time, this loop is just to find where to put it - * - 'loopbreaker' is just here to prevent infinite loops - */ - for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { - /* compute and get midpoint */ - int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ - float midfra = array[mid].time; - - /* check if exactly equal to midpoint */ - if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists = 1; - return mid; - } - - /* repeat in upper/lower half */ - if (frame > midfra) - start = mid + 1; - else if (frame < midfra) - end = mid - 1; - } - - /* print error if loop-limit exceeded */ - if (loopbreaker == (maxloop - 1)) { - printf("Error: binarysearch_fcm_envelopedata_index() was taking too long\n"); - - // include debug info - printf("\tround = %d: start = %d, end = %d, arraylen = %d\n", loopbreaker, start, end, arraylen); - } - - /* not found, so return where to place it */ - return start; -} - /* callback to add new envelope data point */ -// TODO: should we have a separate file for things like this? static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg)) { Scene *scene = CTX_data_scene(C); @@ -425,7 +344,7 @@ static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(ar /* check that no data exists for the current frame... */ if (env->data) { short exists = -1; - int i = binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists); + int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists); /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */ if (exists) diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 4250acf5848..d5fa9ca9a47 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -633,6 +633,82 @@ static void rna_fcurve_range(FCurve *fcu, float range[2]) calc_fcurve_range(fcu, range, range + 1, FALSE, FALSE); } + +static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FModifier *fmod, ReportList *reports, float frame) +{ + FCM_EnvelopeData fed; + FMod_Envelope *env = (FMod_Envelope *)fmod->data; + + /* init template data */ + fed.min = -1.0f; + fed.max = 1.0f; + fed.time = frame; + fed.f1 = fed.f2 = 0; + int i; + + if (env->data) { + /* add point to end of control points */ + short exists = -1; + i = BKE_fcm_envelope_find_index(env->data, frame, env->totvert, &exists); + if (exists) { + BKE_reportf(reports, RPT_ERROR, "Already a control point at frame %.6f", frame); + return NULL; + } + + /* realloc memory for extra point */ + env->data = (FCM_EnvelopeData *) MEM_reallocN((void *)env->data, (env->totvert + 1) * sizeof(FCM_EnvelopeData)); + + /* move the points after the added point */ + if (i < env->totvert) { + memmove(env->data + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData)); + } + + env->totvert++; + } + else { + env->data = MEM_mallocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); + env->totvert = 1; + i = 0; + } + + /* add point to paste at index i */ + *(env->data + i) = fed; + return (env->data + i); +} + +void rna_FModifierEnvelope_points_remove(FModifier *fmod, ReportList *reports, PointerRNA *point) +{ + FCM_EnvelopeData *cp = point->data; + FMod_Envelope *env = (FMod_Envelope *)fmod->data; + + int index = (int)(cp - env->data); + + /* test point is in range */ + if (index < 0 || index >= env->totvert) { + BKE_report(reports, RPT_ERROR, "Control Point not in FEnvelopeModifier"); + return; + } + + if (env->totvert > 1) { + /* move data after the removed point */ + + memmove(env->data + index, env->data + (index + 1), sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1)); + + /* realloc smaller array */ + env->totvert--; + env->data = (FCM_EnvelopeData *) MEM_reallocN((void *)env->data, (env->totvert) * sizeof(FCM_EnvelopeData)); + } + else { + /* just free array, since the only vert was deleted */ + if (env->data) { + MEM_freeN(env->data); + env->data = NULL; + } + env->totvert = 0; + } + RNA_POINTER_INVALIDATE(point); +} + #else static void rna_def_fmodifier_generator(BlenderRNA *brna) @@ -770,6 +846,36 @@ static void rna_def_fmodifier_envelope_ctrl(BlenderRNA *brna) /* - selection flags (not implemented in UI yet though) */ } +static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "FModifierEnvelopeControlPoints"); + srna = RNA_def_struct(brna, "FModifierEnvelopeControlPoints", NULL); + RNA_def_struct_sdna(srna, "FModifier"); + + RNA_def_struct_ui_text(srna, "Control Points", "Control points defining the shape of the envelope"); + + func = RNA_def_function(srna, "add", "rna_FModifierEnvelope_points_add"); + RNA_def_function_ui_description(func, "Add a control point to a FModifierEnvelope"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "", + "Frame to add this control-point", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Newly created control-point"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_FModifierEnvelope_points_remove"); + RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); +} + + static void rna_def_fmodifier_envelope(BlenderRNA *brna) { StructRNA *srna; @@ -784,6 +890,7 @@ static void rna_def_fmodifier_envelope(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "data", "totvert"); RNA_def_property_struct_type(prop, "FModifierEnvelopeControlPoint"); RNA_def_property_ui_text(prop, "Control Points", "Control points defining the shape of the envelope"); + rna_def_fmodifier_envelope_control_points(brna, prop); /* Range Settings */ prop = RNA_def_property(srna, "reference_value", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3