forked from bartvdbraak/blender
patch [#33985] Added FModifierEnvelope control_point add remove to API
from Peter Staples (batfinger)
This commit is contained in:
parent
acf04f003f
commit
b77eccf801
@ -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 -------- */
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user