Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/fcurve.c')
-rw-r--r--source/blender/blenkernel/intern/fcurve.c219
1 files changed, 182 insertions, 37 deletions
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index d747fb0cea2..a2b5a05feac 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -314,23 +314,25 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt,
- bAction **action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve(
+ PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
+ AnimData **r_adt, bAction **r_action, bool *r_driven, bool *r_special)
{
- return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven, r_special);
+ return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **animdata,
- bAction **action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve_context_ui(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
+ AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
- if (animdata) *animdata = NULL;
*r_driven = false;
*r_special = false;
- if (action) *action = NULL;
+ if (r_animdata) *r_animdata = NULL;
+ if (r_action) *r_action = NULL;
/* Special case for NLA Control Curves... */
if (ptr->type == &RNA_NlaStrip) {
@@ -372,8 +374,8 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
if (adt->action && adt->action->curves.first) {
fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
- if (fcu && action)
- *action = adt->action;
+ if (fcu && r_action)
+ *r_action = adt->action;
}
/* if not animated, check if driven */
@@ -381,14 +383,14 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
if (fcu) {
- if (animdata) *animdata = adt;
+ if (r_animdata) *r_animdata = adt;
*r_driven = true;
}
}
- if (fcu && action) {
- if (animdata) *animdata = adt;
- *action = adt->action;
+ if (fcu && r_action) {
+ if (r_animdata) *r_animdata = adt;
+ *r_action = adt->action;
break;
}
else if (step) {
@@ -1149,6 +1151,71 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return value;
}
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
+bool driver_get_variable_property(
+ ChannelDriver *driver, DriverTarget *dtar,
+ PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar))
+ return false;
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: driver has an invalid target to use (path = %s)\n", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
+ ptr = PointerRNA_NULL;
+ prop = NULL; /* ok */
+ }
+ else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* ok */
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path);
+ }
+
+ ptr = PointerRNA_NULL;
+ *r_prop = NULL;
+ *r_index = -1;
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ *r_ptr = ptr;
+ *r_prop = prop;
+ *r_index = index;
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return true;
+}
+
/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
{
@@ -1235,7 +1302,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
mat4_to_quat(q1, pchan->pose_mat);
mat4_to_quat(q2, pchan2->pose_mat);
- invert_qt(q1);
+ invert_qt_normalized(q1);
mul_qt_qtqt(quat, q1, q2);
angle = 2.0f * (saacos(quat[0]));
angle = ABS(angle);
@@ -1533,8 +1600,8 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/* Driver API --------------------------------- */
-/* This frees the driver variable itself */
-void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
+/* Perform actual freeing driver variable and remove it from the given list */
+void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
/* sanity checks */
if (dvar == NULL)
@@ -1554,8 +1621,15 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
DRIVER_TARGETS_LOOPER_END
/* remove the variable from the driver */
- BLI_freelinkN(&driver->variables, dvar);
+ BLI_freelinkN(variables, dvar);
+}
+/* Free the driver variable and do extra updates */
+void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
+
#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
if (driver->type == DRIVER_TYPE_PYTHON)
@@ -1563,6 +1637,24 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
#endif
}
+/* Copy driver variables from src_vars list to dst_vars list */
+void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
+{
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path)
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
@@ -1593,6 +1685,71 @@ void driver_change_variable_type(DriverVar *dvar, int type)
DRIVER_TARGETS_LOOPER_END
}
+/* Validate driver name (after being renamed) */
+void driver_variable_name_validate(DriverVar *dvar)
+{
+ /* Special character blacklist */
+ const char special_char_blacklist[] = {
+ '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-',
+ '/', '\\', '?', ':', ';', '<', '>', '{', '}', '[', ']', '|',
+ ' ', '.', '\t', '\n', '\r'
+ };
+
+ /* sanity checks */
+ if (dvar == NULL)
+ return;
+
+ /* clear all invalid-name flags */
+ dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
+
+ /* 0) Zero-length identifiers are not allowed */
+ if (dvar->name[0] == '\0') {
+ dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
+ }
+
+ /* 1) Must start with a letter */
+ /* XXX: We assume that valid unicode letters in other languages are ok too, hence the blacklisting */
+ if (ELEM(dvar->name[0], '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
+ }
+ else if (dvar->name[0] == '_') {
+ /* NOTE: We don't allow names to start with underscores (i.e. it helps when ruling out security risks) */
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+
+ /* 2) Must not contain invalid stuff in the middle of the string */
+ if (strchr(dvar->name, ' ')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
+ }
+ if (strchr(dvar->name, '.')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
+ }
+
+ /* 3) Check for special characters - Either at start, or in the middle */
+ for (int i = 0; i < sizeof(special_char_blacklist); i++) {
+ char *match = strchr(dvar->name, special_char_blacklist[i]);
+
+ if (match == dvar->name)
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ else if (match != NULL)
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
+ }
+
+ /* 4) Check if the name is a reserved keyword
+ * NOTE: These won't confuse Python, but it will be impossible to use the variable
+ * in an expression without Python misinterpreting what these are for
+ */
+#ifdef WITH_PYTHON
+ if (BPY_string_is_keyword(dvar->name)) {
+ dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
+ }
+#endif
+
+ /* If any these conditions match, the name is invalid */
+ if (dvar->flag & DVAR_ALL_INVALID_FLAGS)
+ dvar->flag |= DVAR_FLAG_INVALID_NAME;
+}
+
/* Add a new driver variable */
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
@@ -1619,7 +1776,7 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
if (driver->type == DRIVER_TYPE_PYTHON)
driver->flag |= DRIVER_FLAG_RENAMEVAR;
#endif
-
+
/* return the target */
return dvar;
}
@@ -1638,7 +1795,7 @@ void fcurve_free_driver(FCurve *fcu)
/* free driver targets */
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
dvarn = dvar->next;
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
}
#ifdef WITH_PYTHON
@@ -1656,7 +1813,6 @@ void fcurve_free_driver(FCurve *fcu)
ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
{
ChannelDriver *ndriver;
- DriverVar *dvar;
/* sanity checks */
if (driver == NULL)
@@ -1667,19 +1823,8 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
ndriver->expr_comp = NULL;
/* copy variables */
- BLI_listbase_clear(&ndriver->variables);
- BLI_duplicatelist(&ndriver->variables, &driver->variables);
-
- for (dvar = ndriver->variables.first; dvar; dvar = dvar->next) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER(dvar)
- {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path)
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- DRIVER_TARGETS_LOOPER_END
- }
+ BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
+ driver_variables_copy(&ndriver->variables, &driver->variables);
/* return the new driver */
return ndriver;
@@ -1714,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
*/
-static float evaluate_driver(ChannelDriver *driver, const float evaltime)
+float evaluate_driver(ChannelDriver *driver, const float evaltime)
{
DriverVar *dvar;
@@ -2436,11 +2581,11 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
float t = fabsf(evaltime - floorf(evaltime));
/* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
- fpt = prevfpt + (int)(evaltime - prevfpt->vec[0]);
+ fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]);
/* if not exactly on the frame, perform linear interpolation with the next one */
- if (t != 0.0f)
- cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], t);
+ if ((t != 0.0f) && (t < 1.0f))
+ cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
else
cvalue = fpt->vec[1];
}