Cleanup: use doxy sections, update comments missed from refactor
This commit is contained in:
@@ -21,12 +21,6 @@
|
|||||||
* \ingroup bke
|
* \ingroup bke
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// #include <float.h>
|
|
||||||
// #include <math.h>
|
|
||||||
// #include <stddef.h>
|
|
||||||
// #include <stdio.h>
|
|
||||||
// #include <string.h>
|
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "DNA_anim_types.h"
|
#include "DNA_anim_types.h"
|
||||||
@@ -66,17 +60,19 @@ static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
|
|||||||
|
|
||||||
static CLG_LogRef LOG = {"bke.fcurve"};
|
static CLG_LogRef LOG = {"bke.fcurve"};
|
||||||
|
|
||||||
/* Driver Variables --------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Variables
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/* TypeInfo for Driver Variables (dvti) */
|
/* TypeInfo for Driver Variables (dvti) */
|
||||||
typedef struct DriverVarTypeInfo {
|
typedef struct DriverVarTypeInfo {
|
||||||
/* evaluation callback */
|
/* Evaluation callback. */
|
||||||
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
|
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
|
||||||
|
|
||||||
/* allocation of target slots */
|
/* Allocation of target slots. */
|
||||||
int num_targets; /* number of target slots required */
|
int num_targets; /* Number of target slots required. */
|
||||||
const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
|
const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots. */
|
||||||
short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
|
short target_flags[MAX_DRIVER_TARGETS]; /* Flags defining the requirements for each slot. */
|
||||||
} DriverVarTypeInfo;
|
} DriverVarTypeInfo;
|
||||||
|
|
||||||
/* Macro to begin definitions */
|
/* Macro to begin definitions */
|
||||||
@@ -85,7 +81,11 @@ typedef struct DriverVarTypeInfo {
|
|||||||
/* Macro to end definitions */
|
/* Macro to end definitions */
|
||||||
#define END_DVAR_TYPEDEF }
|
#define END_DVAR_TYPEDEF }
|
||||||
|
|
||||||
/* ......... */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Target Utilities
|
||||||
|
* \{ */
|
||||||
|
|
||||||
static ID *dtar_id_ensure_proxy_from(ID *id)
|
static ID *dtar_id_ensure_proxy_from(ID *id)
|
||||||
{
|
{
|
||||||
@@ -107,14 +107,14 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||||||
int index = -1;
|
int index = -1;
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
|
|
||||||
/* sanity check */
|
/* Sanity check. */
|
||||||
if (ELEM(NULL, driver, dtar)) {
|
if (ELEM(NULL, driver, dtar)) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
id = dtar_id_ensure_proxy_from(dtar->id);
|
id = dtar_id_ensure_proxy_from(dtar->id);
|
||||||
|
|
||||||
/* error check for missing pointer... */
|
/* Error check for missing pointer. */
|
||||||
if (id == NULL) {
|
if (id == NULL) {
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
||||||
@@ -125,12 +125,12 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get RNA-pointer for the ID-block given in target */
|
/* Get RNA-pointer for the ID-block given in target. */
|
||||||
RNA_id_pointer_create(id, &id_ptr);
|
RNA_id_pointer_create(id, &id_ptr);
|
||||||
|
|
||||||
/* get property to read from, and get value as appropriate */
|
/* Get property to read from, and get value as appropriate. */
|
||||||
if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
||||||
/* path couldn't be resolved */
|
/* Path couldn't be resolved. */
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_ERROR(&LOG,
|
CLOG_ERROR(&LOG,
|
||||||
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
||||||
@@ -144,9 +144,9 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (RNA_property_array_check(prop)) {
|
if (RNA_property_array_check(prop)) {
|
||||||
/* array */
|
/* Array. */
|
||||||
if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
|
if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
|
||||||
/* out of bounds */
|
/* Out of bounds. */
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_ERROR(&LOG,
|
CLOG_ERROR(&LOG,
|
||||||
"Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
|
"Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
|
||||||
@@ -175,7 +175,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* not an array */
|
/* Not an array. */
|
||||||
switch (RNA_property_type(prop)) {
|
switch (RNA_property_type(prop)) {
|
||||||
case PROP_BOOLEAN:
|
case PROP_BOOLEAN:
|
||||||
value = (float)RNA_property_boolean_get(&ptr, prop);
|
value = (float)RNA_property_boolean_get(&ptr, prop);
|
||||||
@@ -194,7 +194,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we're still here, we should be ok... */
|
/* If we're still here, we should be ok. */
|
||||||
dtar->flag &= ~DTAR_FLAG_INVALID;
|
dtar->flag &= ~DTAR_FLAG_INVALID;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -214,14 +214,14 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||||||
ID *id;
|
ID *id;
|
||||||
int index = -1;
|
int index = -1;
|
||||||
|
|
||||||
/* sanity check */
|
/* Sanity check. */
|
||||||
if (ELEM(NULL, driver, dtar)) {
|
if (ELEM(NULL, driver, dtar)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
id = dtar_id_ensure_proxy_from(dtar->id);
|
id = dtar_id_ensure_proxy_from(dtar->id);
|
||||||
|
|
||||||
/* error check for missing pointer... */
|
/* Error check for missing pointer. */
|
||||||
if (id == NULL) {
|
if (id == NULL) {
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
||||||
@@ -232,19 +232,19 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get RNA-pointer for the ID-block given in target */
|
/* Get RNA-pointer for the ID-block given in target. */
|
||||||
RNA_id_pointer_create(id, &id_ptr);
|
RNA_id_pointer_create(id, &id_ptr);
|
||||||
|
|
||||||
/* get property to read from, and get value as appropriate */
|
/* Get property to read from, and get value as appropriate. */
|
||||||
if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
|
if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
|
||||||
ptr = PointerRNA_NULL;
|
ptr = PointerRNA_NULL;
|
||||||
prop = NULL; /* ok */
|
prop = NULL; /* OK. */
|
||||||
}
|
}
|
||||||
else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
||||||
/* ok */
|
/* OK. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* path couldn't be resolved */
|
/* Path couldn't be resolved. */
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_ERROR(&LOG,
|
CLOG_ERROR(&LOG,
|
||||||
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
||||||
@@ -265,7 +265,7 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||||||
*r_prop = prop;
|
*r_prop = prop;
|
||||||
*r_index = index;
|
*r_index = index;
|
||||||
|
|
||||||
/* if we're still here, we should be ok... */
|
/* If we're still here, we should be ok. */
|
||||||
dtar->flag &= ~DTAR_FLAG_INVALID;
|
dtar->flag &= ~DTAR_FLAG_INVALID;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -277,14 +277,14 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||||
|
|
||||||
/* check if this target has valid data */
|
/* Check if this target has valid data. */
|
||||||
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
|
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
|
||||||
/* invalid target, so will not have enough targets */
|
/* Invalid target, so will not have enough targets. */
|
||||||
driver->flag |= DRIVER_FLAG_INVALID;
|
driver->flag |= DRIVER_FLAG_INVALID;
|
||||||
dtar->flag |= DTAR_FLAG_INVALID;
|
dtar->flag |= DTAR_FLAG_INVALID;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* target seems to be OK now... */
|
/* Target seems to be OK now. */
|
||||||
dtar->flag &= ~DTAR_FLAG_INVALID;
|
dtar->flag &= ~DTAR_FLAG_INVALID;
|
||||||
valid_targets++;
|
valid_targets++;
|
||||||
}
|
}
|
||||||
@@ -294,21 +294,25 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
return valid_targets;
|
return valid_targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ......... */
|
/** \} */
|
||||||
|
|
||||||
/* evaluate 'single prop' driver variable */
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Variable Utilities
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
/* Evaluate 'single prop' driver variable. */
|
||||||
static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
|
static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
/* just evaluate the first target slot */
|
/* Just evaluate the first target slot. */
|
||||||
return dtar_get_prop_val(driver, &dvar->targets[0]);
|
return dtar_get_prop_val(driver, &dvar->targets[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* evaluate 'rotation difference' driver variable */
|
/* Evaluate 'rotation difference' driver variable. */
|
||||||
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
short valid_targets = driver_check_valid_targets(driver, dvar);
|
short valid_targets = driver_check_valid_targets(driver, dvar);
|
||||||
|
|
||||||
/* make sure we have enough valid targets to use - all or nothing for now... */
|
/* Make sure we have enough valid targets to use - all or nothing for now. */
|
||||||
if (driver_check_valid_targets(driver, dvar) != 2) {
|
if (driver_check_valid_targets(driver, dvar) != 2) {
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_WARN(&LOG,
|
CLOG_WARN(&LOG,
|
||||||
@@ -324,31 +328,31 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
|
|
||||||
/* NOTE: for now, these are all just worldspace */
|
/* NOTE: for now, these are all just worldspace */
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
/* get pointer to loc values to store in */
|
/* Get pointer to loc values to store in. */
|
||||||
DriverTarget *dtar = &dvar->targets[i];
|
DriverTarget *dtar = &dvar->targets[i];
|
||||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||||
bPoseChannel *pchan;
|
bPoseChannel *pchan;
|
||||||
|
|
||||||
/* after the checks above, the targets should be valid here... */
|
/* After the checks above, the targets should be valid here. */
|
||||||
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
|
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
|
||||||
|
|
||||||
/* try to get posechannel */
|
/* Try to get pose-channel. */
|
||||||
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
|
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
|
||||||
|
|
||||||
/* check if object or bone */
|
/* Check if object or bone. */
|
||||||
if (pchan) {
|
if (pchan) {
|
||||||
/* bone */
|
/* Bone. */
|
||||||
mat[i] = pchan->pose_mat;
|
mat[i] = pchan->pose_mat;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* object */
|
/* Object. */
|
||||||
mat[i] = ob->obmat;
|
mat[i] = ob->obmat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float q1[4], q2[4], quat[4], angle;
|
float q1[4], q2[4], quat[4], angle;
|
||||||
|
|
||||||
/* use the final posed locations */
|
/* Use the final posed locations. */
|
||||||
mat4_to_quat(q1, mat[0]);
|
mat4_to_quat(q1, mat[0]);
|
||||||
mat4_to_quat(q2, mat[1]);
|
mat4_to_quat(q2, mat[1]);
|
||||||
|
|
||||||
@@ -360,15 +364,18 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
|
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* evaluate 'location difference' driver variable */
|
/**
|
||||||
/* TODO: this needs to take into account space conversions... */
|
* Evaluate 'location difference' driver variable.
|
||||||
|
*
|
||||||
|
* TODO: this needs to take into account space conversions.
|
||||||
|
*/
|
||||||
static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
float loc1[3] = {0.0f, 0.0f, 0.0f};
|
float loc1[3] = {0.0f, 0.0f, 0.0f};
|
||||||
float loc2[3] = {0.0f, 0.0f, 0.0f};
|
float loc2[3] = {0.0f, 0.0f, 0.0f};
|
||||||
short valid_targets = driver_check_valid_targets(driver, dvar);
|
short valid_targets = driver_check_valid_targets(driver, dvar);
|
||||||
|
|
||||||
/* make sure we have enough valid targets to use - all or nothing for now... */
|
/* Make sure we have enough valid targets to use - all or nothing for now. */
|
||||||
if (valid_targets < dvar->num_targets) {
|
if (valid_targets < dvar->num_targets) {
|
||||||
if (G.debug & G_DEBUG) {
|
if (G.debug & G_DEBUG) {
|
||||||
CLOG_WARN(&LOG,
|
CLOG_WARN(&LOG,
|
||||||
@@ -381,72 +388,72 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* SECOND PASS: get two location values */
|
/* SECOND PASS: get two location values */
|
||||||
/* NOTE: for now, these are all just worldspace */
|
/* NOTE: for now, these are all just world-space */
|
||||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||||
/* get pointer to loc values to store in */
|
/* Get pointer to loc values to store in. */
|
||||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||||
bPoseChannel *pchan;
|
bPoseChannel *pchan;
|
||||||
float tmp_loc[3];
|
float tmp_loc[3];
|
||||||
|
|
||||||
/* after the checks above, the targets should be valid here... */
|
/* After the checks above, the targets should be valid here. */
|
||||||
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
|
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
|
||||||
|
|
||||||
/* try to get posechannel */
|
/* Try to get pose-channel. */
|
||||||
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
|
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
|
||||||
|
|
||||||
/* check if object or bone */
|
/* Check if object or bone. */
|
||||||
if (pchan) {
|
if (pchan) {
|
||||||
/* bone */
|
/* Bone. */
|
||||||
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
||||||
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
||||||
float mat[4][4];
|
float mat[4][4];
|
||||||
|
|
||||||
/* extract transform just like how the constraints do it! */
|
/* Extract transform just like how the constraints do it! */
|
||||||
copy_m4_m4(mat, pchan->pose_mat);
|
copy_m4_m4(mat, pchan->pose_mat);
|
||||||
BKE_constraint_mat_convertspace(
|
BKE_constraint_mat_convertspace(
|
||||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
||||||
|
|
||||||
/* ... and from that, we get our transform */
|
/* ... and from that, we get our transform. */
|
||||||
copy_v3_v3(tmp_loc, mat[3]);
|
copy_v3_v3(tmp_loc, mat[3]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* transform space (use transform values directly) */
|
/* Transform space (use transform values directly). */
|
||||||
copy_v3_v3(tmp_loc, pchan->loc);
|
copy_v3_v3(tmp_loc, pchan->loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* convert to worldspace */
|
/* Convert to worldspace. */
|
||||||
copy_v3_v3(tmp_loc, pchan->pose_head);
|
copy_v3_v3(tmp_loc, pchan->pose_head);
|
||||||
mul_m4_v3(ob->obmat, tmp_loc);
|
mul_m4_v3(ob->obmat, tmp_loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* object */
|
/* Object. */
|
||||||
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
||||||
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
||||||
/* XXX: this should practically be the same as transform space... */
|
/* XXX: this should practically be the same as transform space. */
|
||||||
float mat[4][4];
|
float mat[4][4];
|
||||||
|
|
||||||
/* extract transform just like how the constraints do it! */
|
/* Extract transform just like how the constraints do it! */
|
||||||
copy_m4_m4(mat, ob->obmat);
|
copy_m4_m4(mat, ob->obmat);
|
||||||
BKE_constraint_mat_convertspace(
|
BKE_constraint_mat_convertspace(
|
||||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
||||||
|
|
||||||
/* ... and from that, we get our transform */
|
/* ... and from that, we get our transform. */
|
||||||
copy_v3_v3(tmp_loc, mat[3]);
|
copy_v3_v3(tmp_loc, mat[3]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* transform space (use transform values directly) */
|
/* Transform space (use transform values directly). */
|
||||||
copy_v3_v3(tmp_loc, ob->loc);
|
copy_v3_v3(tmp_loc, ob->loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* worldspace */
|
/* World-space. */
|
||||||
copy_v3_v3(tmp_loc, ob->obmat[3]);
|
copy_v3_v3(tmp_loc, ob->obmat[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy the location to the right place */
|
/* Copy the location to the right place. */
|
||||||
if (tarIndex) {
|
if (tarIndex) {
|
||||||
copy_v3_v3(loc2, tmp_loc);
|
copy_v3_v3(loc2, tmp_loc);
|
||||||
}
|
}
|
||||||
@@ -456,13 +463,14 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
}
|
}
|
||||||
DRIVER_TARGETS_LOOPER_END;
|
DRIVER_TARGETS_LOOPER_END;
|
||||||
|
|
||||||
/* if we're still here, there should now be two targets to use,
|
/* If we're still here, there should now be two targets to use,
|
||||||
* so just take the length of the vector between these points
|
* so just take the length of the vector between these points. */
|
||||||
*/
|
|
||||||
return len_v3v3(loc1, loc2);
|
return len_v3v3(loc1, loc2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* evaluate 'transform channel' driver variable */
|
/**
|
||||||
|
* Evaluate 'transform channel' driver variable.
|
||||||
|
*/
|
||||||
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
DriverTarget *dtar = &dvar->targets[0];
|
DriverTarget *dtar = &dvar->targets[0];
|
||||||
@@ -473,15 +481,15 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
bool use_eulers = false;
|
bool use_eulers = false;
|
||||||
short rot_order = ROT_MODE_EUL;
|
short rot_order = ROT_MODE_EUL;
|
||||||
|
|
||||||
/* check if this target has valid data */
|
/* Check if this target has valid data. */
|
||||||
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
|
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
|
||||||
/* invalid target, so will not have enough targets */
|
/* Invalid target, so will not have enough targets. */
|
||||||
driver->flag |= DRIVER_FLAG_INVALID;
|
driver->flag |= DRIVER_FLAG_INVALID;
|
||||||
dtar->flag |= DTAR_FLAG_INVALID;
|
dtar->flag |= DTAR_FLAG_INVALID;
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* target should be valid now */
|
/* Target should be valid now. */
|
||||||
dtar->flag &= ~DTAR_FLAG_INVALID;
|
dtar->flag &= ~DTAR_FLAG_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +503,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
* but #DTAR_FLAG_LOCAL_CONSTS is for all the common "corrective-shapes-for-limbs" situations.
|
* but #DTAR_FLAG_LOCAL_CONSTS is for all the common "corrective-shapes-for-limbs" situations.
|
||||||
*/
|
*/
|
||||||
if (pchan) {
|
if (pchan) {
|
||||||
/* bone */
|
/* Bone. */
|
||||||
if (pchan->rotmode > 0) {
|
if (pchan->rotmode > 0) {
|
||||||
copy_v3_v3(oldEul, pchan->eul);
|
copy_v3_v3(oldEul, pchan->eul);
|
||||||
rot_order = pchan->rotmode;
|
rot_order = pchan->rotmode;
|
||||||
@@ -504,16 +512,15 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
|
|
||||||
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
||||||
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
||||||
/* just like how the constraints do it! */
|
/* Just like how the constraints do it! */
|
||||||
copy_m4_m4(mat, pchan->pose_mat);
|
copy_m4_m4(mat, pchan->pose_mat);
|
||||||
BKE_constraint_mat_convertspace(
|
BKE_constraint_mat_convertspace(
|
||||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* specially calculate local matrix, since chan_mat is not valid
|
/* Specially calculate local matrix, since chan_mat is not valid
|
||||||
* since it stores delta transform of pose_mat so that deforms work
|
* since it stores delta transform of pose_mat so that deforms work
|
||||||
* so it cannot be used here for "transform" space
|
* so it cannot be used here for "transform" space. */
|
||||||
*/
|
|
||||||
BKE_pchan_to_mat4(pchan, mat);
|
BKE_pchan_to_mat4(pchan, mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,7 +530,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* object */
|
/* Object. */
|
||||||
if (ob->rotmode > 0) {
|
if (ob->rotmode > 0) {
|
||||||
copy_v3_v3(oldEul, ob->rot);
|
copy_v3_v3(oldEul, ob->rot);
|
||||||
rot_order = ob->rotmode;
|
rot_order = ob->rotmode;
|
||||||
@@ -532,25 +539,25 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
|
|
||||||
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
|
||||||
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
|
||||||
/* just like how the constraints do it! */
|
/* Just like how the constraints do it! */
|
||||||
copy_m4_m4(mat, ob->obmat);
|
copy_m4_m4(mat, ob->obmat);
|
||||||
BKE_constraint_mat_convertspace(
|
BKE_constraint_mat_convertspace(
|
||||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* transforms to matrix */
|
/* Transforms to matrix. */
|
||||||
BKE_object_to_mat4(ob, mat);
|
BKE_object_to_mat4(ob, mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* worldspace matrix - just the good-old one */
|
/* World-space matrix - just the good-old one. */
|
||||||
copy_m4_m4(mat, ob->obmat);
|
copy_m4_m4(mat, ob->obmat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check which transform */
|
/* Check which transform. */
|
||||||
if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
|
if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
|
||||||
/* not valid channel */
|
/* Not valid channel. */
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
|
else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
|
||||||
@@ -567,7 +574,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
|
return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
|
||||||
}
|
}
|
||||||
else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
|
else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
|
||||||
/* extract rotation as eulers (if needed)
|
/* Extract rotation as eulers (if needed)
|
||||||
* - definitely if rotation order isn't eulers already
|
* - definitely if rotation order isn't eulers already
|
||||||
* - if eulers, then we have 2 options:
|
* - if eulers, then we have 2 options:
|
||||||
* a) decompose transform matrix as required, then try to make eulers from
|
* a) decompose transform matrix as required, then try to make eulers from
|
||||||
@@ -596,7 +603,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||||||
return quat[channel];
|
return quat[channel];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* extract location and choose right axis */
|
/* Extract location and choose right axis. */
|
||||||
return mat[3][dtar->transChan];
|
return mat[3][dtar->transChan];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,41 +673,45 @@ void BKE_driver_target_matrix_to_rot_channels(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ......... */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Variable Type Info
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/* Table of Driver Variable Type Info Data */
|
/* Table of Driver Variable Type Info Data */
|
||||||
static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
|
static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
|
||||||
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
|
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* Eval callback. */
|
||||||
1, /* number of targets used */
|
1, /* Number of targets used. */
|
||||||
{"Property"}, /* UI names for targets */
|
{"Property"}, /* UI names for targets */
|
||||||
{0} /* flags */
|
{0} /* Flags. */
|
||||||
END_DVAR_TYPEDEF,
|
END_DVAR_TYPEDEF,
|
||||||
|
|
||||||
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
|
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* Eval callback. */
|
||||||
2, /* number of targets used */
|
2, /* Number of targets used. */
|
||||||
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
|
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
|
||||||
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
|
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
|
||||||
DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
|
DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
|
||||||
END_DVAR_TYPEDEF,
|
END_DVAR_TYPEDEF,
|
||||||
|
|
||||||
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
|
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* Eval callback. */
|
||||||
2, /* number of targets used */
|
2, /* Number of targets used. */
|
||||||
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
|
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
|
||||||
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
|
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
|
||||||
DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
|
DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
|
||||||
END_DVAR_TYPEDEF,
|
END_DVAR_TYPEDEF,
|
||||||
|
|
||||||
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
|
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* Eval callback. */
|
||||||
1, /* number of targets used */
|
1, /* Number of targets used. */
|
||||||
{"Object/Bone"}, /* UI names for targets */
|
{"Object/Bone"}, /* UI names for targets */
|
||||||
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
|
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
|
||||||
END_DVAR_TYPEDEF,
|
END_DVAR_TYPEDEF,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Get driver variable typeinfo */
|
/* Get driver variable typeinfo */
|
||||||
static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
|
static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
|
||||||
{
|
{
|
||||||
/* check if valid type */
|
/* Check if valid type. */
|
||||||
if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
|
if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
|
||||||
return &dvar_types[type];
|
return &dvar_types[type];
|
||||||
}
|
}
|
||||||
@@ -709,40 +720,44 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver API --------------------------------- */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver API
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/* Perform actual freeing driver variable and remove it from the given list */
|
/* Perform actual freeing driver variable and remove it from the given list */
|
||||||
void driver_free_variable(ListBase *variables, DriverVar *dvar)
|
void driver_free_variable(ListBase *variables, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
/* sanity checks */
|
/* Sanity checks. */
|
||||||
if (dvar == NULL) {
|
if (dvar == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free target vars
|
/* Free target vars:
|
||||||
* - need to go over all of them, not just up to the ones that are used
|
* - need to go over all of them, not just up to the ones that are used
|
||||||
* currently, since there may be some lingering RNA paths from
|
* currently, since there may be some lingering RNA paths from
|
||||||
* previous users needing freeing
|
* previous users needing freeing
|
||||||
*/
|
*/
|
||||||
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
|
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
|
||||||
/* free RNA path if applicable */
|
/* Free RNA path if applicable. */
|
||||||
if (dtar->rna_path) {
|
if (dtar->rna_path) {
|
||||||
MEM_freeN(dtar->rna_path);
|
MEM_freeN(dtar->rna_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DRIVER_TARGETS_LOOPER_END;
|
DRIVER_TARGETS_LOOPER_END;
|
||||||
|
|
||||||
/* remove the variable from the driver */
|
/* Remove the variable from the driver. */
|
||||||
BLI_freelinkN(variables, dvar);
|
BLI_freelinkN(variables, dvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the driver variable and do extra updates */
|
/* Free the driver variable and do extra updates */
|
||||||
void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
|
void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
/* remove and free the driver variable */
|
/* Remove and free the driver variable. */
|
||||||
driver_free_variable(&driver->variables, dvar);
|
driver_free_variable(&driver->variables, dvar);
|
||||||
|
|
||||||
/* since driver variables are cached, the expression needs re-compiling too */
|
/* Since driver variables are cached, the expression needs re-compiling too. */
|
||||||
BKE_driver_invalidate_expression(driver, false, true);
|
BKE_driver_invalidate_expression(driver, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,9 +768,9 @@ void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
|
|||||||
BLI_duplicatelist(dst_vars, src_vars);
|
BLI_duplicatelist(dst_vars, src_vars);
|
||||||
|
|
||||||
LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
|
LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
|
||||||
/* need to go over all targets so that we don't leave any dangling paths */
|
/* Need to go over all targets so that we don't leave any dangling paths. */
|
||||||
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
|
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
|
||||||
/* make a copy of target's rna path if available */
|
/* Make a copy of target's rna path if available. */
|
||||||
if (dtar->rna_path) {
|
if (dtar->rna_path) {
|
||||||
dtar->rna_path = MEM_dupallocN(dtar->rna_path);
|
dtar->rna_path = MEM_dupallocN(dtar->rna_path);
|
||||||
}
|
}
|
||||||
@@ -769,25 +784,24 @@ void driver_change_variable_type(DriverVar *dvar, int type)
|
|||||||
{
|
{
|
||||||
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
|
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
|
||||||
|
|
||||||
/* sanity check */
|
/* Sanity check. */
|
||||||
if (ELEM(NULL, dvar, dvti)) {
|
if (ELEM(NULL, dvar, dvti)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the new settings */
|
/* Set the new settings. */
|
||||||
dvar->type = type;
|
dvar->type = type;
|
||||||
dvar->num_targets = dvti->num_targets;
|
dvar->num_targets = dvti->num_targets;
|
||||||
|
|
||||||
/* make changes to the targets based on the defines for these types
|
/* Make changes to the targets based on the defines for these types.
|
||||||
* NOTE: only need to make sure the ones we're using here are valid...
|
* NOTE: only need to make sure the ones we're using here are valid. */
|
||||||
*/
|
|
||||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||||
short flags = dvti->target_flags[tarIndex];
|
short flags = dvti->target_flags[tarIndex];
|
||||||
|
|
||||||
/* store the flags */
|
/* Store the flags. */
|
||||||
dtar->flag = flags;
|
dtar->flag = flags;
|
||||||
|
|
||||||
/* object ID types only, or idtype not yet initialized */
|
/* Object ID types only, or idtype not yet initialized. */
|
||||||
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
|
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
|
||||||
dtar->idtype = ID_OB;
|
dtar->idtype = ID_OB;
|
||||||
}
|
}
|
||||||
@@ -804,12 +818,12 @@ void driver_variable_name_validate(DriverVar *dvar)
|
|||||||
'?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
|
'?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sanity checks */
|
/* Sanity checks. */
|
||||||
if (dvar == NULL) {
|
if (dvar == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear all invalid-name flags */
|
/* Clear all invalid-name flags. */
|
||||||
dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
|
dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
|
||||||
|
|
||||||
/* 0) Zero-length identifiers are not allowed */
|
/* 0) Zero-length identifiers are not allowed */
|
||||||
@@ -870,16 +884,16 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
|
|||||||
{
|
{
|
||||||
DriverVar *dvar;
|
DriverVar *dvar;
|
||||||
|
|
||||||
/* sanity checks */
|
/* Sanity checks. */
|
||||||
if (driver == NULL) {
|
if (driver == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make a new variable */
|
/* Make a new variable. */
|
||||||
dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
|
dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
|
||||||
BLI_addtail(&driver->variables, dvar);
|
BLI_addtail(&driver->variables, dvar);
|
||||||
|
|
||||||
/* give the variable a 'unique' name */
|
/* Give the variable a 'unique' name. */
|
||||||
strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
|
strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
|
||||||
BLI_uniquename(&driver->variables,
|
BLI_uniquename(&driver->variables,
|
||||||
dvar,
|
dvar,
|
||||||
@@ -888,13 +902,13 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
|
|||||||
offsetof(DriverVar, name),
|
offsetof(DriverVar, name),
|
||||||
sizeof(dvar->name));
|
sizeof(dvar->name));
|
||||||
|
|
||||||
/* set the default type to 'single prop' */
|
/* Set the default type to 'single prop'. */
|
||||||
driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
|
driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
|
||||||
|
|
||||||
/* since driver variables are cached, the expression needs re-compiling too */
|
/* Since driver variables are cached, the expression needs re-compiling too. */
|
||||||
BKE_driver_invalidate_expression(driver, false, true);
|
BKE_driver_invalidate_expression(driver, false, true);
|
||||||
|
|
||||||
/* return the target */
|
/* Return the target. */
|
||||||
return dvar;
|
return dvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,20 +918,20 @@ void fcurve_free_driver(FCurve *fcu)
|
|||||||
ChannelDriver *driver;
|
ChannelDriver *driver;
|
||||||
DriverVar *dvar, *dvarn;
|
DriverVar *dvar, *dvarn;
|
||||||
|
|
||||||
/* sanity checks */
|
/* Sanity checks. */
|
||||||
if (ELEM(NULL, fcu, fcu->driver)) {
|
if (ELEM(NULL, fcu, fcu->driver)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver = fcu->driver;
|
driver = fcu->driver;
|
||||||
|
|
||||||
/* free driver targets */
|
/* Free driver targets. */
|
||||||
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
|
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
|
||||||
dvarn = dvar->next;
|
dvarn = dvar->next;
|
||||||
driver_free_variable_ex(driver, dvar);
|
driver_free_variable_ex(driver, dvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
/* free compiled driver expression */
|
/* Free compiled driver expression. */
|
||||||
if (driver->expr_comp) {
|
if (driver->expr_comp) {
|
||||||
BPY_DECREF(driver->expr_comp);
|
BPY_DECREF(driver->expr_comp);
|
||||||
}
|
}
|
||||||
@@ -936,27 +950,31 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
|
|||||||
{
|
{
|
||||||
ChannelDriver *ndriver;
|
ChannelDriver *ndriver;
|
||||||
|
|
||||||
/* sanity checks */
|
/* Sanity checks. */
|
||||||
if (driver == NULL) {
|
if (driver == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy all data */
|
/* Copy all data. */
|
||||||
ndriver = MEM_dupallocN(driver);
|
ndriver = MEM_dupallocN(driver);
|
||||||
ndriver->expr_comp = NULL;
|
ndriver->expr_comp = NULL;
|
||||||
ndriver->expr_simple = NULL;
|
ndriver->expr_simple = NULL;
|
||||||
|
|
||||||
/* copy variables */
|
/* Copy variables. */
|
||||||
|
|
||||||
/* to get rid of refs to non-copied data (that's still used on original) */
|
/* To get rid of refs to non-copied data (that's still used on original). */
|
||||||
BLI_listbase_clear(&ndriver->variables);
|
BLI_listbase_clear(&ndriver->variables);
|
||||||
driver_variables_copy(&ndriver->variables, &driver->variables);
|
driver_variables_copy(&ndriver->variables, &driver->variables);
|
||||||
|
|
||||||
/* return the new driver */
|
/* Return the new driver. */
|
||||||
return ndriver;
|
return ndriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver Expression Evaluation --------------- */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Expression Evaluation
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/* Index constants for the expression parameter array. */
|
/* Index constants for the expression parameter array. */
|
||||||
enum {
|
enum {
|
||||||
@@ -1026,7 +1044,7 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver,
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* arriving here means a bug, not user error */
|
/* Arriving here means a bug, not user error. */
|
||||||
CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
|
CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1135,22 +1153,25 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver Evaluation -------------------------- */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Driver Evaluation
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/* Evaluate a Driver Variable to get a value that contributes to the final */
|
/* Evaluate a Driver Variable to get a value that contributes to the final */
|
||||||
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
|
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
|
||||||
{
|
{
|
||||||
const DriverVarTypeInfo *dvti;
|
const DriverVarTypeInfo *dvti;
|
||||||
|
|
||||||
/* sanity check */
|
/* Sanity check. */
|
||||||
if (ELEM(NULL, driver, dvar)) {
|
if (ELEM(NULL, driver, dvar)) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call the relevant callbacks to get the variable value
|
/* Call the relevant callbacks to get the variable value
|
||||||
* using the variable type info, storing the obtained value
|
* using the variable type info, storing the obtained value
|
||||||
* in dvar->curval so that drivers can be debugged
|
* in `dvar->curval` so that drivers can be debugged. */
|
||||||
*/
|
|
||||||
dvti = get_dvar_typeinfo(dvar->type);
|
dvti = get_dvar_typeinfo(dvar->type);
|
||||||
|
|
||||||
if (dvti && dvti->get_value) {
|
if (dvti && dvti->get_value) {
|
||||||
@@ -1167,25 +1188,25 @@ static void evaluate_driver_sum(ChannelDriver *driver)
|
|||||||
{
|
{
|
||||||
DriverVar *dvar;
|
DriverVar *dvar;
|
||||||
|
|
||||||
/* check how many variables there are first (i.e. just one?) */
|
/* Check how many variables there are first (i.e. just one?). */
|
||||||
if (BLI_listbase_is_single(&driver->variables)) {
|
if (BLI_listbase_is_single(&driver->variables)) {
|
||||||
/* just one target, so just use that */
|
/* Just one target, so just use that. */
|
||||||
dvar = driver->variables.first;
|
dvar = driver->variables.first;
|
||||||
driver->curval = driver_get_variable_value(driver, dvar);
|
driver->curval = driver_get_variable_value(driver, dvar);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* more than one target, so average the values of the targets */
|
/* More than one target, so average the values of the targets. */
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
int tot = 0;
|
int tot = 0;
|
||||||
|
|
||||||
/* loop through targets, adding (hopefully we don't get any overflow!) */
|
/* Loop through targets, adding (hopefully we don't get any overflow!). */
|
||||||
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
||||||
value += driver_get_variable_value(driver, dvar);
|
value += driver_get_variable_value(driver, dvar);
|
||||||
tot++;
|
tot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* perform operations on the total if appropriate */
|
/* Perform operations on the total if appropriate. */
|
||||||
if (driver->type == DRIVER_TYPE_AVERAGE) {
|
if (driver->type == DRIVER_TYPE_AVERAGE) {
|
||||||
driver->curval = tot ? (value / (float)tot) : 0.0f;
|
driver->curval = tot ? (value / (float)tot) : 0.0f;
|
||||||
}
|
}
|
||||||
@@ -1199,34 +1220,34 @@ static void evaluate_driver_min_max(ChannelDriver *driver)
|
|||||||
DriverVar *dvar;
|
DriverVar *dvar;
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
|
|
||||||
/* loop through the variables, getting the values and comparing them to existing ones */
|
/* Loop through the variables, getting the values and comparing them to existing ones. */
|
||||||
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
||||||
/* get value */
|
/* Get value. */
|
||||||
float tmp_val = driver_get_variable_value(driver, dvar);
|
float tmp_val = driver_get_variable_value(driver, dvar);
|
||||||
|
|
||||||
/* store this value if appropriate */
|
/* Store this value if appropriate. */
|
||||||
if (dvar->prev) {
|
if (dvar->prev) {
|
||||||
/* check if greater/smaller than the baseline */
|
/* Check if greater/smaller than the baseline. */
|
||||||
if (driver->type == DRIVER_TYPE_MAX) {
|
if (driver->type == DRIVER_TYPE_MAX) {
|
||||||
/* max? */
|
/* Max? */
|
||||||
if (tmp_val > value) {
|
if (tmp_val > value) {
|
||||||
value = tmp_val;
|
value = tmp_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* min? */
|
/* Min? */
|
||||||
if (tmp_val < value) {
|
if (tmp_val < value) {
|
||||||
value = tmp_val;
|
value = tmp_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* first item - make this the baseline for comparisons */
|
/* First item - make this the baseline for comparisons. */
|
||||||
value = tmp_val;
|
value = tmp_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store value in driver */
|
/* Store value in driver. */
|
||||||
driver->curval = value;
|
driver->curval = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,16 +1256,15 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
|
|||||||
ChannelDriver *driver_orig,
|
ChannelDriver *driver_orig,
|
||||||
const AnimationEvalContext *anim_eval_context)
|
const AnimationEvalContext *anim_eval_context)
|
||||||
{
|
{
|
||||||
/* check for empty or invalid expression */
|
/* Check for empty or invalid expression. */
|
||||||
if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
|
if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
|
||||||
driver->curval = 0.0f;
|
driver->curval = 0.0f;
|
||||||
}
|
}
|
||||||
else if (!driver_try_evaluate_simple_expr(
|
else if (!driver_try_evaluate_simple_expr(
|
||||||
driver, driver_orig, &driver->curval, anim_eval_context->eval_time)) {
|
driver, driver_orig, &driver->curval, anim_eval_context->eval_time)) {
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
/* this evaluates the expression using Python, and returns its result:
|
/* This evaluates the expression using Python, and returns its result:
|
||||||
* - on errors it reports, then returns 0.0f
|
* - on errors it reports, then returns 0.0f. */
|
||||||
*/
|
|
||||||
BLI_mutex_lock(&python_driver_lock);
|
BLI_mutex_lock(&python_driver_lock);
|
||||||
|
|
||||||
driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, anim_eval_context);
|
driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, anim_eval_context);
|
||||||
@@ -1256,41 +1276,43 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
|
/**
|
||||||
* - "evaltime" is the frame at which F-Curve is being evaluated
|
* Evaluate an Channel-Driver to get a 'time' value to use
|
||||||
* - has to return a float value
|
* instead of `anim_eval_context->eval_time`.
|
||||||
* - driver_orig is where we cache Python expressions, in case of COW
|
*
|
||||||
|
* - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
|
||||||
|
* - Has to return a float value.
|
||||||
|
* - \a driver_orig is where we cache Python expressions, in case of COW
|
||||||
*/
|
*/
|
||||||
float evaluate_driver(PathResolvedRNA *anim_rna,
|
float evaluate_driver(PathResolvedRNA *anim_rna,
|
||||||
ChannelDriver *driver,
|
ChannelDriver *driver,
|
||||||
ChannelDriver *driver_orig,
|
ChannelDriver *driver_orig,
|
||||||
const AnimationEvalContext *anim_eval_context)
|
const AnimationEvalContext *anim_eval_context)
|
||||||
{
|
{
|
||||||
/* check if driver can be evaluated */
|
/* Check if driver can be evaluated. */
|
||||||
if (driver_orig->flag & DRIVER_FLAG_INVALID) {
|
if (driver_orig->flag & DRIVER_FLAG_INVALID) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (driver->type) {
|
switch (driver->type) {
|
||||||
case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
|
case DRIVER_TYPE_AVERAGE: /* Average values of driver targets. */
|
||||||
case DRIVER_TYPE_SUM: /* sum values of driver targets */
|
case DRIVER_TYPE_SUM: /* Sum values of driver targets. */
|
||||||
evaluate_driver_sum(driver);
|
evaluate_driver_sum(driver);
|
||||||
break;
|
break;
|
||||||
case DRIVER_TYPE_MIN: /* smallest value */
|
case DRIVER_TYPE_MIN: /* Smallest value. */
|
||||||
case DRIVER_TYPE_MAX: /* largest value */
|
case DRIVER_TYPE_MAX: /* Largest value. */
|
||||||
evaluate_driver_min_max(driver);
|
evaluate_driver_min_max(driver);
|
||||||
break;
|
break;
|
||||||
case DRIVER_TYPE_PYTHON: /* expression */
|
case DRIVER_TYPE_PYTHON: /* Expression. */
|
||||||
evaluate_driver_python(anim_rna, driver, driver_orig, anim_eval_context);
|
evaluate_driver_python(anim_rna, driver, driver_orig, anim_eval_context);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* special 'hack' - just use stored value
|
/* Special 'hack' - just use stored value
|
||||||
* This is currently used as the mechanism which allows animated settings to be able
|
* This is currently used as the mechanism which allows animated settings to be able
|
||||||
* to be changed via the UI.
|
* to be changed via the UI. */
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return value for driver */
|
/* Return value for driver. */
|
||||||
return driver->curval;
|
return driver->curval;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,8 +411,10 @@ static PyObject *bpy_pydriver_depsgraph_as_pyobject(struct Depsgraph *depsgraph)
|
|||||||
return pyrna_struct_CreatePyObject(&depsgraph_ptr);
|
return pyrna_struct_CreatePyObject(&depsgraph_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds a variable 'depsgraph' to the driver variables. This can then be used to obtain evaluated
|
/**
|
||||||
* datablocks, and the current view layer and scene. See T75553. */
|
* Adds a variable 'depsgraph' to the driver variables. This can then be used to obtain evaluated
|
||||||
|
* data-blocks, and the current view layer and scene. See T75553.
|
||||||
|
*/
|
||||||
static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
|
static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
|
||||||
struct Depsgraph *depsgraph)
|
struct Depsgraph *depsgraph)
|
||||||
{
|
{
|
||||||
@@ -428,17 +430,18 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This evals py driver expressions, 'expr' is a Python expression that
|
/**
|
||||||
* should evaluate to a float number, which is returned.
|
* This evaluates Python driver expressions, `driver_orig->expression`
|
||||||
|
* is a Python expression that should evaluate to a float number, which is returned.
|
||||||
*
|
*
|
||||||
* (old)note: PyGILState_Ensure() isn't always called because python can call
|
* (old)note: PyGILState_Ensure() isn't always called because python can call
|
||||||
* the bake operator which intern starts a thread which calls scene update
|
* the bake operator which intern starts a thread which calls scene update
|
||||||
* which does a driver update. to avoid a deadlock check PyC_IsInterpreterActive()
|
* which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
|
||||||
* if PyGILState_Ensure() is needed - see [#27683]
|
* if #PyGILState_Ensure() is needed, see T27683.
|
||||||
*
|
*
|
||||||
* (new)note: checking if python is running is not threadsafe [#28114]
|
* (new)note: checking if python is running is not thread-safe T28114
|
||||||
* now release the GIL on python operator execution instead, using
|
* now release the GIL on python operator execution instead, using
|
||||||
* PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender.
|
* #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
|
||||||
*
|
*
|
||||||
* For copy-on-write we always cache expressions and write errors in the
|
* For copy-on-write we always cache expressions and write errors in the
|
||||||
* original driver, otherwise these would get freed while editing. Due to
|
* original driver, otherwise these would get freed while editing. Due to
|
||||||
|
|||||||
Reference in New Issue
Block a user