Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/fcurve.c
| Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_nla.h" | #include "BKE_nla.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "atomic_ops.h" | #include "atomic_ops.h" | ||||
| #include "CLG_log.h" | |||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| #include "BPY_extern.h" | #include "BPY_extern.h" | ||||
| #endif | #endif | ||||
| #define SMALL -1.0e-10 | #define SMALL -1.0e-10 | ||||
| #define SELECT 1 | #define SELECT 1 | ||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; | static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; | ||||
| #endif | #endif | ||||
| static CLG_LogRef LOG = {"bke.fcurve"}; | |||||
| /* ************************** Data-Level Functions ************************* */ | /* ************************** Data-Level Functions ************************* */ | ||||
| /* ---------------------- Freeing --------------------------- */ | /* ---------------------- Freeing --------------------------- */ | ||||
| /* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */ | /* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */ | ||||
| void free_fcurve(FCurve *fcu) | void free_fcurve(FCurve *fcu) | ||||
| { | { | ||||
| if (fcu == NULL) | if (fcu == NULL) | ||||
| ▲ Show 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | static int binarysearch_bezt_index_ex(BezTriple array[], float frame, int arraylen, float threshold, bool *r_replace) | ||||
| /* initialize replace-flag first */ | /* initialize replace-flag first */ | ||||
| *r_replace = false; | *r_replace = false; | ||||
| /* sneaky optimizations (don't go through searching process if...): | /* 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 is to be added out of current bounds | ||||
| * - keyframe to be added would replace one of the existing ones on bounds | * - keyframe to be added would replace one of the existing ones on bounds | ||||
| */ | */ | ||||
| if ((arraylen <= 0) || (array == NULL)) { | if ((arraylen <= 0) || (array == NULL)) { | ||||
| printf("Warning: binarysearch_bezt_index() encountered invalid array\n"); | CLOG_WARN(&LOG, "encountered invalid array"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| else { | else { | ||||
| /* check whether to add before/after/on */ | /* check whether to add before/after/on */ | ||||
| float framenum; | float framenum; | ||||
| /* 'First' Keyframe (when only one keyframe, this case is used) */ | /* 'First' Keyframe (when only one keyframe, this case is used) */ | ||||
| framenum = array[0].vec[1][0]; | framenum = array[0].vec[1][0]; | ||||
| Show All 33 Lines | for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { | ||||
| if (frame > midfra) | if (frame > midfra) | ||||
| start = mid + 1; | start = mid + 1; | ||||
| else if (frame < midfra) | else if (frame < midfra) | ||||
| end = mid - 1; | end = mid - 1; | ||||
| } | } | ||||
| /* print error if loop-limit exceeded */ | /* print error if loop-limit exceeded */ | ||||
| if (loopbreaker == (maxloop - 1)) { | if (loopbreaker == (maxloop - 1)) { | ||||
| printf("Error: binarysearch_bezt_index() was taking too long\n"); | CLOG_ERROR(&LOG, "search taking too long"); | ||||
| /* include debug info */ | /* include debug info */ | ||||
| printf("\tround = %d: start = %d, end = %d, arraylen = %d\n", loopbreaker, start, end, arraylen); | CLOG_ERROR(&LOG, "\tround = %d: start = %d, end = %d, arraylen = %d", loopbreaker, start, end, arraylen); | ||||
| } | } | ||||
| /* not found, so return where to place it */ | /* not found, so return where to place it */ | ||||
| return start; | return start; | ||||
| } | } | ||||
| /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve) | /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve) | ||||
| ▲ Show 20 Lines • Show All 345 Lines • ▼ Show 20 Lines | |||||
| * used to retrieve the values to store. | * used to retrieve the values to store. | ||||
| */ | */ | ||||
| void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb) | void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb) | ||||
| { | { | ||||
| FPoint *fpt, *new_fpt; | FPoint *fpt, *new_fpt; | ||||
| int cfra; | int cfra; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| /* TODO: make these tests report errors using reports not printf's */ | /* TODO: make these tests report errors using reports not CLOG's */ | ||||
| if (ELEM(NULL, fcu, sample_cb)) { | if (ELEM(NULL, fcu, sample_cb)) { | ||||
| printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); | CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake"); | ||||
| return; | return; | ||||
| } | } | ||||
| if (start > end) { | if (start > end) { | ||||
| printf("Error: Frame range for Sampled F-Curve creation is inappropriate\n"); | CLOG_ERROR(&LOG, "Error: Frame range for Sampled F-Curve creation is inappropriate"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* set up sample data */ | /* set up sample data */ | ||||
| fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"); | fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"); | ||||
| /* use the sampling callback at 1-frame intervals from start to end frames */ | /* use the sampling callback at 1-frame intervals from start to end frames */ | ||||
| for (cfra = start; cfra <= end; cfra++, fpt++) { | for (cfra = start; cfra <= end; cfra++, fpt++) { | ||||
| ▲ Show 20 Lines • Show All 294 Lines • ▼ Show 20 Lines | static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) | ||||
| 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) { | ||||
| printf("Error: driver has an invalid target to use (path = %s)\n", dtar->rna_path); | CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); | ||||
| } | } | ||||
| 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; | ||||
| } | } | ||||
| /* get RNA-pointer for the ID-block given in target */ | /* get RNA-pointer for the ID-block given in target */ | ||||
| Show All 16 Lines | if (RNA_property_array_check(prop)) { | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* out of bounds */ | /* out of bounds */ | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", | CLOG_ERROR(&LOG, "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", | ||||
| id->name, dtar->rna_path, index); | id->name, dtar->rna_path, index); | ||||
| } | } | ||||
| 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 { | ||||
| Show All 14 Lines | else { | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* path couldn't be resolved */ | /* path couldn't be resolved */ | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path); | CLOG_ERROR(&LOG, "Driver Evaluation Error: cannot resolve target for %s -> %s", id->name, dtar->rna_path); | ||||
| } | } | ||||
| 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; | ||||
| } | } | ||||
| /* if we're still here, we should be ok... */ | /* if we're still here, we should be ok... */ | ||||
| Show All 18 Lines | bool driver_get_variable_property( | ||||
| 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) { | ||||
| printf("Error: driver has an invalid target to use (path = %s)\n", dtar->rna_path); | CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); | ||||
| } | } | ||||
| driver->flag |= DRIVER_FLAG_INVALID; | driver->flag |= DRIVER_FLAG_INVALID; | ||||
| dtar->flag |= DTAR_FLAG_INVALID; | dtar->flag |= DTAR_FLAG_INVALID; | ||||
| 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) { | ||||
| printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path); | CLOG_ERROR(&LOG, "Driver Evaluation Error: cannot resolve target for %s -> %s", id->name, dtar->rna_path); | ||||
| } | } | ||||
| ptr = PointerRNA_NULL; | ptr = PointerRNA_NULL; | ||||
| *r_prop = NULL; | *r_prop = NULL; | ||||
| *r_index = -1; | *r_index = -1; | ||||
| driver->flag |= DRIVER_FLAG_INVALID; | driver->flag |= DRIVER_FLAG_INVALID; | ||||
| dtar->flag |= DTAR_FLAG_INVALID; | dtar->flag |= DTAR_FLAG_INVALID; | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
| /* 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) { | ||||
| printf("RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n", | CLOG_WARN(&LOG, "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", | ||||
| valid_targets, dvar->targets[0].id, dvar->targets[1].id); | valid_targets, dvar->targets[0].id, dvar->targets[1].id); | ||||
| } | } | ||||
| return 0.0f; | return 0.0f; | ||||
| } | } | ||||
| float (*mat[2])[4]; | float (*mat[2])[4]; | ||||
| /* 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++) { | ||||
| Show All 39 Lines | |||||
| { | { | ||||
| 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) { | ||||
| printf("LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n", | CLOG_WARN(&LOG, "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", | ||||
| valid_targets, dvar->targets[0].id, dvar->targets[1].id); | valid_targets, dvar->targets[0].id, dvar->targets[1].id); | ||||
| } | } | ||||
| return 0.0f; | return 0.0f; | ||||
| } | } | ||||
| /* 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 worldspace */ | ||||
| DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) | DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 507 Lines • ▼ Show 20 Lines | case EXPR_PYLIKE_SUCCESS: | ||||
| if (isfinite(result_val)) { | if (isfinite(result_val)) { | ||||
| *result = (float)result_val; | *result = (float)result_val; | ||||
| } | } | ||||
| return true; | return true; | ||||
| case EXPR_PYLIKE_DIV_BY_ZERO: | case EXPR_PYLIKE_DIV_BY_ZERO: | ||||
| case EXPR_PYLIKE_MATH_ERROR: | case EXPR_PYLIKE_MATH_ERROR: | ||||
| message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; | message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; | ||||
| fprintf(stderr, "\n%s in Driver: '%s'\n", message, driver->expression); | CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression); | ||||
| driver->flag |= DRIVER_FLAG_INVALID; | driver->flag |= DRIVER_FLAG_INVALID; | ||||
| return true; | return true; | ||||
| default: | default: | ||||
| /* arriving here means a bug, not user error */ | /* arriving here means a bug, not user error */ | ||||
| printf("Error: simple driver expression evaluation failed: '%s'\n", driver->expression); | CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression); | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| /* Compile and cache the driver expression if necessary, with thread safety. */ | /* Compile and cache the driver expression if necessary, with thread safety. */ | ||||
| static bool driver_compile_simple_expr(ChannelDriver *driver) | static bool driver_compile_simple_expr(ChannelDriver *driver) | ||||
| { | { | ||||
| if (driver->expr_simple != NULL) { | if (driver->expr_simple != NULL) { | ||||
| ▲ Show 20 Lines • Show All 919 Lines • Show Last 20 Lines | |||||