102 const bool only_selected_keys)
110 if ((fcu ==
nullptr) || (fcu->
bezt ==
nullptr) || (fcu->
totvert == 0) ||
111 (!cleardefault && fcu->
totvert == 1))
117 old_bezts = fcu->
bezt;
127 lastb->
f1 = lastb->
f2 = lastb->
f3 = 0;
133 for (
i = 1;
i < totCount;
i++) {
134 float prev[2], cur[2],
next[2];
137 if (
i < (totCount - 1)) {
138 beztn = (old_bezts + (
i + 1));
147 bezt = (old_bezts +
i);
150 prev[0] = lastb->
vec[1][0];
151 prev[1] = lastb->
vec[1][1];
152 cur[0] = bezt->
vec[1][0];
153 cur[1] = bezt->
vec[1][1];
155 if (only_selected_keys && !(bezt->
f2 &
SELECT)) {
158 lastb->
f1 = lastb->
f2 = lastb->
f3 = 0;
163 if (
IS_EQT(cur[0], prev[0], thresh)) {
170 if (cur[1] >
next[1]) {
171 if (
IS_EQT(cur[1], prev[1], thresh) == 0) {
179 if (
IS_EQT(cur[1], prev[1], thresh) == 0) {
189 if (
IS_EQT(cur[1], prev[1], thresh) == 0) {
193 else if (
IS_EQT(cur[1],
next[1], thresh) == 0) {
200 if (
IS_EQT(cur[1], prev[1], thresh) == 0) {
215 if (cleardefault && fcu->
totvert == 1) {
216 float default_value = 0.0f;
228 if (fcu->
bezt->
vec[1][1] == default_value) {
249 const int start_index,
250 int *r_segment_start_idx,
253 *r_segment_start_idx = 0;
256 bool in_segment =
false;
258 for (
int i = start_index;
i < fcu->
totvert;
i++) {
264 *r_segment_start_idx =
i;
269 else if (in_segment) {
283 ListBase segments = {
nullptr,
nullptr};
290 int segment_start_idx = 0;
292 int current_index = 0;
297 segment->start_index = segment_start_idx;
298 segment->length = segment_len;
300 current_index = segment_start_idx + segment_len;
307 const BezTriple *start_bezt = index - 1 >= 0 ? &fcu->
bezt[index - 1] : &fcu->
bezt[index];
329 const float lerp_factor =
fabs(factor);
331 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
332 const float key_y_value =
interpf(target_bezt->
vec[1][1], fcu->
bezt[
i].
vec[1][1], lerp_factor);
343 float default_value = 0;
374 return default_value;
394 const float key_y_value =
interpf(default_value, fcu->
bezt[
i].
vec[1][1], factor);
406 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
410 const float y_average =
y / segment->length;
412 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
413 const float key_y_value =
interpf(y_average, fcu->
bezt[
i].
vec[1][1], 1 - factor);
428 "Butterworth Coefficients");
445 const float sampling_frequency,
448 double s = double(sampling_frequency);
449 const double a =
tan(
M_PI * cutoff_frequency / s);
450 const double a2 = a * a;
454 s = a2 + 2.0 * a * r + 1.0;
455 bw_coeff->
A[
i] = a2 / s;
456 bw_coeff->
d1[
i] = 2.0 * (1 - a2) / s;
457 bw_coeff->
d2[
i] = -(a2 - 2.0 * a * r + 1.0) / s;
465 w0[
i] = bw_coeff->
d1[
i] * w1[
i] + bw_coeff->
d2[
i] * w2[
i] +
x;
466 x = bw_coeff->
A[
i] * (w0[
i] + 2.0 * w1[
i] + w2[
i]);
474 const float *filtered_values,
475 const int start_index,
477 const int sample_index,
478 const int blend_in_out)
480 if (start_index == end_index || blend_in_out == 0) {
481 return samples[start_index];
484 const float blend_in_y_samples = samples[start_index];
485 const float blend_out_y_samples = samples[end_index];
487 const float blend_in_y_filtered = filtered_values[start_index + blend_in_out];
488 const float blend_out_y_filtered = filtered_values[end_index - blend_in_out];
490 const float slope_in_samples = samples[start_index] - samples[start_index - 1];
491 const float slope_out_samples = samples[end_index] - samples[end_index + 1];
492 const float slope_in_filtered = filtered_values[start_index + blend_in_out - 1] -
493 filtered_values[start_index + blend_in_out];
494 const float slope_out_filtered = filtered_values[end_index - blend_in_out] -
495 filtered_values[end_index - blend_in_out - 1];
497 if (sample_index - start_index <= blend_in_out) {
498 const int blend_index = sample_index - start_index;
499 const float blend_in_out_factor =
clamp_f(
float(blend_index) / blend_in_out, 0.0f, 1.0f);
500 const float blend_value =
interpf(blend_in_y_filtered +
501 slope_in_filtered * (blend_in_out - blend_index),
502 blend_in_y_samples + slope_in_samples * blend_index,
503 blend_in_out_factor);
506 if (end_index - sample_index <= blend_in_out) {
507 const int blend_index = end_index - sample_index;
508 const float blend_in_out_factor =
clamp_f(
float(blend_index) / blend_in_out, 0.0f, 1.0f);
509 const float blend_value =
interpf(blend_out_y_filtered +
510 slope_out_filtered * (blend_in_out - blend_index),
511 blend_out_y_samples + slope_out_samples * blend_index,
512 blend_in_out_factor);
521 const int sample_count,
523 const int blend_in_out,
524 const int sample_rate,
530 "Butterworth Filtered FCurve Values");
538 const float fwd_offset = samples[0];
540 for (
int i = 0;
i < sample_count;
i++) {
541 const double x = double(samples[
i] - fwd_offset);
543 filtered_values[
i] =
float(filtered_value) + fwd_offset;
546 for (
int i = 0;
i < filter_order;
i++) {
552 const float bwd_offset = filtered_values[sample_count - 1];
555 for (
int i = sample_count - 1;
i >= 0;
i--) {
556 const double x = double(filtered_values[
i] - bwd_offset);
558 filtered_values[
i] =
float(filtered_value) + bwd_offset;
561 const int segment_end_index = segment->start_index + segment->length;
565 const int samples_start_index = filter_order * sample_rate;
566 const int samples_end_index = int(right_bezt.
vec[1][0] - left_bezt.
vec[1][0] + filter_order) *
569 const int blend_in_out_clamped =
min_ii(blend_in_out,
570 (samples_end_index - samples_start_index) / 2);
572 for (
int i = segment->start_index;
i < segment_end_index;
i++) {
573 float blend_in_out_factor;
574 if (blend_in_out_clamped == 0) {
575 blend_in_out_factor = 1;
578 blend_in_out_factor =
min_ff(
float(
i - segment->start_index) / blend_in_out_clamped, 1.0f);
581 blend_in_out_factor =
min_ff(
float(segment_end_index -
i - 1) / blend_in_out_clamped, 1.0f);
584 const float x_delta = fcu->
bezt[
i].
vec[1][0] - left_bezt.
vec[1][0] + filter_order;
587 const int filter_index =
round(x_delta * sample_rate);
593 blend_in_out_clamped);
595 const float blended_value =
interpf(
596 filtered_values[filter_index], blend_value, blend_in_out_factor);
597 const float key_y_value =
interpf(blended_value, samples[filter_index], factor);
614 const double sigma_sq = 2.0 * sigma * sigma;
617 for (
int i = 0;
i < kernel_size;
i++) {
618 const double normalized_index = double(
i) / (kernel_size - 1);
619 r_kernel[
i] =
exp(-normalized_index * normalized_index / sigma_sq);
626 sum += r_kernel[
i] * 2;
631 for (
int i = 0;
i < kernel_size;
i++) {
638 const float *original_values,
640 const int sample_count,
642 const int kernel_size,
643 const double *kernel)
645 const int segment_end_index = segment->start_index + segment->length;
646 const float segment_start_x = fcu->
bezt[segment->start_index].
vec[1][0];
647 float *filtered_samples =
static_cast<float *
>(
MEM_dupallocN(samples));
648 for (
int i = kernel_size;
i < sample_count - kernel_size;
i++) {
650 double filter_result = samples[
i] * kernel[0];
651 for (
int j = 1; j <= kernel_size; j++) {
652 const double kernel_value = kernel[j];
653 filter_result += samples[
i + j] * kernel_value;
654 filter_result += samples[
i - j] * kernel_value;
656 filtered_samples[
i] = filter_result;
659 for (
int i = segment->start_index;
i < segment_end_index;
i++) {
660 const float sample_index_f = (fcu->
bezt[
i].
vec[1][0] - segment_start_x) + kernel_size;
663 const int sample_index =
round(sample_index_f);
667 const int secondary_index =
clamp_i(
668 sample_index +
signum_i(sample_index_f - sample_index), 0, sample_count - 1);
670 const float filter_result =
interpf(filtered_samples[secondary_index],
671 filtered_samples[sample_index],
672 std::abs(sample_index_f - sample_index));
673 const float key_y_value =
interpf(
674 filter_result, original_values[
i - segment->start_index], factor);
683 const float x_shift = (
x - shift) * width;
684 const float y = x_shift /
sqrt(1 +
pow2f(x_shift));
686 return (
y + 1) * 0.5f;
697 const float key_x_range = right_key->
vec[1][0] - left_key->
vec[1][0];
698 const float key_y_range = right_key->
vec[1][1] - left_key->
vec[1][1];
702 if (
IS_EQF(key_x_range, 0.0f)) {
707 const float shift = -factor;
711 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
713 const float x = ((fcu->
bezt[
i].
vec[1][0] - left_key->
vec[1][0]) / key_x_range) * 2 - 1;
717 const float blend = (
y - y_min) * (1 / (y_max - y_min));
719 const float key_y_value = left_key->
vec[1][1] + key_y_range *
blend;
734 const BezTriple segment_last_key = fcu->
bezt[segment->start_index + segment->length - 1];
735 y_delta = right_key->
vec[1][1] - segment_last_key.
vec[1][1];
738 const BezTriple segment_first_key = fcu->
bezt[segment->start_index];
739 y_delta = left_key->
vec[1][1] - segment_first_key.
vec[1][1];
742 const float offset_value = y_delta *
fabs(factor);
743 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
744 const float key_y_value = fcu->
bezt[
i].
vec[1][1] + offset_value;
751static float s_curve(
float x,
float slope,
float width,
float height,
float xshift,
float yshift)
758 float y = height *
pow((
x - xshift), slope) /
759 (
pow((
x - xshift), slope) +
pow((width - (
x - xshift)), slope)) +
763 if (
x > xshift + width) {
766 else if (
x < xshift) {
777 const float key_x_range = right_key->
vec[1][0] - left_key->
vec[1][0];
778 const float key_y_range = right_key->
vec[1][1] - left_key->
vec[1][1];
782 if (
IS_EQF(key_x_range, 0.0f)) {
786 const float slope = 3.0;
788 const float width = 2.0;
789 const float height = 2.0;
800 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
802 const float x = (fcu->
bezt[
i].
vec[1][0] - left_key->
vec[1][0]) / key_x_range;
803 const float ease =
s_curve(
x, slope, width, height, xy_shift, xy_shift);
804 const float base = left_key->
vec[1][1] + key_y_range * ease;
808 y_delta = base - fcu->
bezt[
i].
vec[1][1];
811 y_delta = fcu->
bezt[
i].
vec[1][1] - base;
814 const float key_y_value = fcu->
bezt[
i].
vec[1][1] + y_delta * factor;
831 if (segment->start_index + segment->length >= fcu->
totvert - 1) {
834 reference_key = right_key;
835 beyond_key = fcu->
bezt[segment->start_index + segment->length + 1];
839 if (segment->start_index <= 1) {
842 reference_key = left_key;
843 beyond_key = fcu->
bezt[segment->start_index - 2];
848 const float y_delta = beyond_key.
vec[1][1] - reference_key->
vec[1][1];
849 const float x_delta = beyond_key.
vec[1][0] - reference_key->
vec[1][0];
856 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
860 const float new_x_delta = fcu->
bezt[
i].
vec[1][0] - reference_key->
vec[1][0];
861 const float new_y_delta = new_x_delta * y_delta / x_delta;
863 const float delta = reference_key->
vec[1][1] + new_y_delta - fcu->
bezt[
i].
vec[1][1];
865 const float key_y_value = fcu->
bezt[
i].
vec[1][1] + delta *
fabs(factor);
881 const float key_x_range = right_key->
vec[1][0] - left_key->
vec[1][0];
882 const float key_y_range = right_key->
vec[1][1] - left_key->
vec[1][1];
886 if (
IS_EQF(key_x_range, 0.0f)) {
890 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
894 normalized_x = (fcu->
bezt[
i].
vec[1][0] - left_key->
vec[1][0]) / key_x_range;
897 normalized_x = (right_key->
vec[1][0] - fcu->
bezt[
i].
vec[1][0]) / key_x_range;
900 const float y_delta = key_y_range * normalized_x;
902 const float key_y_value = fcu->
bezt[
i].
vec[1][1] + y_delta * factor;
914 const float key_x_range = right_key->
vec[1][0] - left_key->
vec[1][0];
915 const float key_y_range = right_key->
vec[1][1] - left_key->
vec[1][1];
919 if (
IS_EQF(key_x_range, 0.0f)) {
923 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
925 const float normalized_x = (fcu->
bezt[
i].
vec[1][0] - left_key->
vec[1][0]) / key_x_range;
927 const float linear = left_key->
vec[1][1] + key_y_range * normalized_x;
929 const float delta = fcu->
bezt[
i].
vec[1][1] - linear;
931 const float key_y_value = linear + delta * factor;
944 const float fcu_x_range = last_key->
vec[1][0] - first_key->
vec[1][0];
945 const float fcu_y_range = last_key->
vec[1][1] - first_key->
vec[1][1];
947 const float first_key_x = first_key->
vec[1][0];
953 for (
int i = 0;
i < segment->length;
i++) {
955 const float time = fcu->
bezt[segment->start_index +
i].
vec[1][0] + frame_offset;
957 const float wrapped_time =
floored_fmod(time - first_key_x, fcu_x_range) + first_key_x;
958 const float delta_y = fcu_y_range *
floorf((time - first_key_x) / fcu_x_range);
960 const float key_y_value =
evaluate_fcurve(fcu, wrapped_time) + delta_y;
961 y_values[
i] = key_y_value;
964 for (
int i = 0;
i < segment->length;
i++) {
987 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
988 const float key_y_value =
interpf(fcu->
bezt[
i].
vec[1][1], reference_key->
vec[1][1], factor);
999 segment->start_index + segment->length);
1001 const float lerp_factor = (factor + 1) / 2;
1002 for (
int i = segment->start_index;
i < segment->start_index + segment->length;
i++) {
1003 const float key_y_value =
interpf(right_bezt->
vec[1][1], left_bezt->
vec[1][1], lerp_factor);
1052 int bezt_segment_start_idx,
1053 int bezt_segment_len,
1057 int selected_len = bezt_segment_len;
1063 if (bezt_segment_len + bezt_segment_start_idx != fcu->
totvert &&
1069 bezt_segment_start_idx--;
1073 const int target_fcurve_verts =
ceil(bezt_segment_len - selected_len * remove_ratio);
1083 target_fcurve_verts);
1090 if (fcu ==
nullptr || fcu->
bezt ==
nullptr || fcu->
totvert == 0) {
1096 bool can_decimate_all_selected =
true;
1101 can_decimate_all_selected =
false;
1111 fcu, segment->start_index, segment->length, remove_ratio, error_sq_max);
1116 fcu->
bezt =
nullptr;
1119 for (
int i = 0;
i < old_totvert;
i++) {
1131 return can_decimate_all_selected;
1150 if (fcu->
bezt ==
nullptr) {
1156 for (
int i = 0;
i < fcu->
totvert;
i++, bezt++) {
1171 for (
int i = 0,
x = 0; (
i < fcu->
totvert) && (
x < totSel);
i++, bezt++) {
1174 tsb->
h1 = &bezt->
vec[0][1];
1175 tsb->
h2 = &bezt->
vec[1][1];
1176 tsb->
h3 = &bezt->
vec[2][1];
1179 if (
x < totSel - 1) {
1197 for (
int i = 0;
i < totSel;
i++, tsb++) {
1200 if (
ELEM(
i, 0, (totSel - 1)) == 0) {
1202 const tSmooth_Bezt *tP2 = (
i - 2 > 0) ? (tsb - 2) : (
nullptr);
1204 const tSmooth_Bezt *tN2 = (
i + 2 < totSel) ? (tsb + 2) : (
nullptr);
1206 const float p1 = *tP1->
h2;
1207 const float p2 = (tP2) ? (*tP2->
h2) : (*tP1->
h2);
1208 const float c1 = *tsb->
h2;
1209 const float n1 = *tN1->
h2;
1210 const float n2 = (tN2) ? (*tN2->
h2) : (*tN1->
h2);
1213 tsb->
y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
1214 tsb->
y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
1216 tsb->
y2 = (tsb->
y1 + tsb->
y3) / 2;
1222 for (
int i = 0;
i < totSel;
i++, tsb++) {
1224 if (
ELEM(
i, 0, (totSel - 1)) == 0) {
1229 *tsb->
h1 = ((*tsb->
h1) * 0.7f) + (tsb->
y1 * 0.3f);
1230 *tsb->
h3 = ((*tsb->
h3) * 0.7f) + (tsb->
y3 * 0.3f);
1273 return channelbag->
fcurves().size() == 1;
1300 if (identifier == slot_identifier) {
1311 std::cout <<
"KeyframeCopyBuffer contents:" << std::endl;
1313 std::cout <<
" scene frame: " << this->
current_frame << std::endl;
1316 std::cout <<
" buffer is empty" << std::endl;
1320 std::cout <<
" buffer has single F-Curve" << std::endl;
1324 std::cout <<
" channelbags: " <<
keyframe_data.channelbags().size() << std::endl;
1327 const std::string &slot_identifier = this->
slot_identifiers.lookup(channelbag->slot_handle);
1329 std::cout <<
" - Channelbag for slotless F-Curves:" << std::endl;
1332 std::cout <<
" - Channelbag for slot \"" << slot_identifier <<
"\":" << std::endl;
1334 for (
const FCurve *fcurve : channelbag->fcurves()) {
1335 std::cout <<
" " << fcurve->rna_path <<
"[" << fcurve->array_index <<
"]";
1337 std::cout <<
" (bone)";
1339 std::cout << std::endl;
1387 return pchan !=
nullptr;
1392using namespace blender;
1393using namespace blender::animrig;
1394using namespace blender::ed::animation;
1411 KeyframeCopyBuffer &buffer;
1414 Map<std::pair<const Action *, slot_handle_t>,
slot_handle_t> orig_to_buffer_slots;
1431 Channelbag &channelbag_for_ale(
const bAnimListElem *ale)
1434 const Action *map_key_action;
1441 map_key_action =
nullptr;
1442 map_key_handle = SLOTLESS_SLOT_HANDLE;
1445 const auto map_key = std::make_pair(map_key_action, map_key_handle);
1447 if (
const std::optional<slot_handle_t> opt_internal_slot_handle =
1448 this->orig_to_buffer_slots.
lookup_try(map_key))
1451 const slot_handle_t internal_slot_handle = *opt_internal_slot_handle;
1455 internal_slot_handle);
1456 BLI_assert_msg(channelbag,
"If the slot exists, so should the channelbag");
1464 internal_slot_handle);
1465 this->orig_to_buffer_slots.
add_new(map_key, internal_slot_handle);
1468 StringRef slot_identifier;
1469 if (map_key_action) {
1471 BLI_assert_msg(ale_slot,
"Slot for copied keyframes is expected to exist.");
1510 const_cast<FCurve *
>(fcu),
1518 Channelbag &channelbag = slot_mapper.channelbag_for_ale(ale);
1540 for (; bezt_index < fcu->
totvert; bezt_index++, bezt++) {
1551 const float bezt_frame = bezt->
vec[1][0];
1567namespace blender::ed::animation {
1571 int ofs_start, ofs_end;
1581 const std::string bone_name = rna_path.
substr(ofs_start, ofs_end - ofs_start);
1585 return rna_path.
substr(0, ofs_start) + bname_new + rna_path.
substr(ofs_end);
1589 const FCurve &fcurve_to_match,
1590 const FCurve &fcurve_in_copy_buffer,
1600enum class SlotMatchMethod {
1608 SELECTION_AND_IDENTIFIER = 3,
1618 const bool to_single,
1622 "The from-single-to-single case is expected to be implemented as a special case "
1623 "in `paste_animedit_keys()`");
1633 return SlotMatchMethod::IDENTIFIER;
1639 return SlotMatchMethod::SELECTION;
1645 return SlotMatchMethod::SELECTION_AND_IDENTIFIER;
1656 return SlotMatchMethod::NONE;
1668 "If any keyframes were copied, they MUST have come from some slot.");
1669 if (num_slots_copied > 1) {
1671 return SlotMatchMethod::IDENTIFIER;
1674 return SlotMatchMethod::NONE;
1686 const bool from_single,
1687 const bool to_single,
1693 const FCurve &fcurve_to_match = *
static_cast<FCurve *
>(ale_to_paste_into.
data);
1696 "The from-single-to-single case is expected to be implemented as a special case "
1697 "in `paste_animedit_keys()`");
1701 const Channelbag *single_copy_buffer_channelbag;
1706 const Slot *ale_slot =
nullptr;
1707 const Action *ale_action =
nullptr;
1724 switch (slot_match) {
1725 case SlotMatchMethod::SELECTION:
1731 case SlotMatchMethod::NONE:
1736 case SlotMatchMethod::SELECTION_AND_IDENTIFIER:
1742 case SlotMatchMethod::IDENTIFIER: {
1744 const std::string target_slot_identifier = ale_slot ?
1749 target_slot_identifier);
1750 if (!single_copy_buffer_channelbag) {
1763 for (
const Channelbag *channelbag : channelbags_to_paste_from) {
1771 paste_context.
flip))
1782 const FCurve &fcurve_to_match,
1783 const FCurve &fcurve_in_copy_buffer,
1785 const bool from_single,
1786 const bool to_single,
1797 const bool is_source_ok = from_single ||
1799 if (!is_source_ok) {
1806 return with_flipped_name && with_flipped_name == fcurve_to_match.
rna_path;
1813 const FCurve &fcurve_to_match,
1814 const FCurve &fcurve_in_copy_buffer,
1816 const bool from_single,
1827 const bool is_source_ok = from_single ||
1829 if (!is_source_ok) {
1840 slot_handle_in_copy_buffer);
1843 "paste_animedit_keys: no idea which ID was animated by \"%s\" in slot \"%s\", so cannot "
1844 "match by property name\n",
1849 ID *animated_id = optional_id.value();
1853 printf(
"paste_animedit_keys: error ID has been removed!\n");
1862 printf(
"paste_animedit_keys: failed to resolve path id:%s, '%s'!\n",
1874 const FCurve &fcurve_to_match,
1875 const FCurve &fcurve_in_copy_buffer,
1877 const bool from_single,
1895 const size_t slength = strlen(fcurve.
rna_path);
1917 bezt.
vec[0][1] = -bezt.
vec[0][1];
1918 bezt.
vec[1][1] = -bezt.
vec[1][1];
1919 bezt.
vec[2][1] = -bezt.
vec[2][1];
1925 const FCurve &fcurve_in_copy_buffer,
1939 switch (merge_mode) {
1955 f_min = fcurve_in_copy_buffer.
bezt[0].
vec[1][0] + offset[0];
1956 f_max = fcurve_in_copy_buffer.
bezt[fcurve_in_copy_buffer.
totvert - 1].
vec[1][0] +
1965 if (f_min < f_max) {
1968 if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
1981 for (
i = 0, bezt = fcurve_in_copy_buffer.
bezt;
i < fcurve_in_copy_buffer.
totvert;
i++, bezt++) {
2013 "Paste keys starting at current frame"},
2019 "Paste keys relative to the current frame when copying"},
2021 {0,
nullptr, 0,
nullptr,
nullptr},
2029 "Paste keys with the first key matching the key left of the cursor"},
2034 "Paste keys with the last key matching the key right of the cursor"},
2038 "Current Frame Value",
2039 "Paste keys relative to the value of the curve under the cursor"},
2044 "Paste keys relative to the Y-Position of the cursor"},
2049 "Paste keys with the same value as they were copied"},
2050 {0,
nullptr, 0,
nullptr,
nullptr},
2060 "Overwrite keys in pasted range"},
2064 "Overwrite Entire Range",
2065 "Overwrite keys in pasted range, using the range of all copied keys"},
2066 {0,
nullptr, 0,
nullptr,
nullptr},
2070 const FCurve &fcurve_in_copy_buffer,
2078 switch (value_offset_mode) {
2081 const float offset = sipo->
cursorVal - fcurve_in_copy_buffer.
bezt[0].
vec[1][1];
2087 const float offset = cfra_y - fcurve_in_copy_buffer.
bezt[0].
vec[1][1];
2096 const float offset = left_key.
vec[1][1] - fcurve_in_copy_buffer.
bezt[0].
vec[1][1];
2105 const float offset = right_key.
vec[1][1] -
2106 fcurve_in_copy_buffer.
bezt[fcurve_in_copy_buffer.
totvert - 1].
vec[1][1];
2133 float offset[2] = {0, 0};
2151 if (from_single && to_single) {
2155 const FCurve &fcurve_in_copy_buffer =
2163 fcu, fcurve_in_copy_buffer, offset, paste_context.
merge_mode,
false);
2180 bool found_match =
false;
2185 matcher, ac->
bmain, *ale, from_single, to_single, paste_context);
2186 if (!fcurve_in_copy_buffer) {
2198 *fcurve_in_copy_buffer,
2201 paste_context.
flip);
Functions and classes to work with Actions.
Functions to work with AnimData.
Functions to modify FCurves.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
unsigned int BKE_curve_decimate_bezt_array(BezTriple *bezt_array, unsigned int bezt_array_len, unsigned int resolu, bool is_cyclic, char flag_test, char flag_set, float error_sq_max, unsigned int error_target_len)
FCurve * BKE_fcurve_create()
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
void BKE_fcurve_handles_recalc(FCurve *fcu)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_delete_keys_selected(FCurve *fcu)
void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, float new_value)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_delete_keys_all(FCurve *fcu)
ListBase * which_libbase(Main *bmain, short type)
float BKE_scene_frame_get(const Scene *scene)
#define BLI_assert_msg(a, msg)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
MINLINE int min_ii(int a, int b)
MINLINE float pow2f(float x)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float floored_fmod(float f, float n)
MINLINE float interpf(float target, float origin, float t)
MINLINE int clamp_i(int value, int min, int max)
MINLINE int signum_i(float a)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
int bool bool bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t str_len) ATTR_NONNULL(1
bool BLI_str_quoted_substr_range(const char *__restrict str, const char *__restrict prefix, int *__restrict r_start, int *__restrict r_end) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
size_t BLI_string_flip_side_name(char *name_dst, const char *name_src, bool strip_number, size_t name_dst_maxncpy) ATTR_NONNULL(1
#define UNUSED_VARS_NDEBUG(...)
@ INSERTKEY_OVERWRITE_FULL
#define BEZT_ISSEL_IDX(bezt, i)
#define BEZT_SEL_ALL(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZT_DESEL_ALL(bezt)
Object is a sort of wrapper for general info.
#define ANIM_UPDATE_DEFAULT
@ KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL
@ KEYFRAME_PASTE_MERGE_OVER_RANGE
@ KEYFRAME_PASTE_MERGE_OVER
@ KEYFRAME_PASTE_MERGE_MIX
@ KEYFRAME_PASTE_VALUE_OFFSET_RIGHT_KEY
@ KEYFRAME_PASTE_VALUE_OFFSET_NONE
@ KEYFRAME_PASTE_VALUE_OFFSET_CURSOR
@ KEYFRAME_PASTE_VALUE_OFFSET_CFRA
@ KEYFRAME_PASTE_VALUE_OFFSET_LEFT_KEY
@ KEYFRAME_PASTE_OFFSET_NONE
@ KEYFRAME_PASTE_OFFSET_CFRA_END
@ KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ KEYFRAME_PASTE_NOTHING_TO_PASTE
@ KEYFRAME_PASTE_NOWHERE_TO_PASTE
Read Guarded memory(de)allocation.
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
static T sum(const btAlignedObjectArray< T > &items)
bool add(const Key &key, const Value &value)
void add_new(const Key &key, const Value &value)
bool contains(const Key &key) const
std::optional< Value > lookup_try(const Key &key) const
void add_new(const Key &key, const Value &value)
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool endswith(StringRef suffix) const
constexpr const char * c_str() const
Slot * slot_for_handle(slot_handle_t handle)
bool fcurve_assign_to_channel_group(FCurve &fcurve, bActionGroup &to_group)
void fcurve_append(FCurve &fcurve)
blender::Span< const FCurve * > fcurves() const
bActionGroup & channel_group_ensure(StringRefNull name)
const Channelbag * channelbag_for_slot(const Slot &slot) const
Channelbag & channelbag_for_slot_add(const Slot &slot)
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
void smooth_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float *original_values, float *samples, const int sample_count, const float factor, const int kernel_size, const double *kernel)
void ED_anim_calculate_butterworth_coefficients(const float cutoff_frequency, const float sampling_frequency, ButterworthCoefficients *bw_coeff)
static bool prepare_for_decimate(FCurve *fcu, int i)
static float butterworth_calculate_blend_value(float *samples, const float *filtered_values, const int start_index, const int end_index, const int sample_index, const int blend_in_out)
void butterworth_smooth_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float *samples, const int sample_count, const float factor, const int blend_in_out, const int sample_rate, ButterworthCoefficients *bw_coeff)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
static const BezTriple * fcurve_segment_end_get(FCurve *fcu, int index)
static bool is_animating_bone(const bAnimListElem *ale)
float get_default_rna_value(const FCurve *fcu, PropertyRNA *prop, PointerRNA *ptr)
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
void ANIM_fcurves_copybuf_reset()
void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
static bool find_fcurve_segment(FCurve *fcu, const int start_index, int *r_segment_start_idx, int *r_segment_len)
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
void ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor, const float width)
bool copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
ButterworthCoefficients * ED_anim_allocate_butterworth_coefficients(const int filter_order)
void time_offset_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float frame_offset)
void ED_ANIM_get_1d_gauss_kernel(const float sigma, const int kernel_size, double *r_kernel)
static float paste_get_y_offset(const bAnimContext *ac, const FCurve &fcurve_in_copy_buffer, const bAnimListElem *ale, const eKeyPasteValueOffset value_offset_mode)
void scale_average_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
void blend_offset_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
const EnumPropertyItem rna_enum_keyframe_paste_offset_value_items[]
void clean_fcurve(bAnimListElem *ale, float thresh, bool cleardefault, const bool only_selected_keys)
eKeyPasteError paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const KeyframePasteContext &paste_context)
void shear_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor, tShearDirection direction)
void ANIM_fcurves_copybuf_free()
static const BezTriple * fcurve_segment_start_get(FCurve *fcu, int index)
static float ease_sigmoid_function(const float x, const float width, const float shift)
void blend_to_ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
static void decimate_fcurve_segment(FCurve *fcu, int bezt_segment_start_idx, int bezt_segment_len, float remove_ratio, float error_sq_max)
static double butterworth_filter_value(double x, double *w0, double *w1, double *w2, ButterworthCoefficients *bw_coeff)
bool match_slope_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
void smooth_fcurve(FCurve *fcu)
void push_pull_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
void blend_to_default_fcurve(PointerRNA *id_ptr, FCurve *fcu, const float factor)
static float s_curve(float x, float slope, float width, float height, float xshift, float yshift)
ListBase find_fcurve_segments(FCurve *fcu)
bool duplicate_fcurve_keys(FCurve *fcu)
void scale_from_fcurve_segment_neighbor(FCurve *fcu, FCurveSegment *segment, const float factor, const FCurveSegmentAnchor anchor)
void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
void ED_anim_free_butterworth_coefficients(ButterworthCoefficients *bw_coeff)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
ccl_device_inline float2 fabs(const float2 a)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
decltype(::ActionSlot::handle) slot_handle_t
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
Lesser Key-framing API call.
bool(*)(Main *bmain, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t slot_handle_in_copy_buffer, bool from_single, bool to_single, bool flip) pastebuf_match_func
KeyframeCopyBuffer * keyframe_copy_buffer
static void paste_animedit_keys_fcurve(FCurve *fcu, const FCurve &fcurve_in_copy_buffer, float offset[2], const eKeyMergeMode merge_mode, bool flip)
bool pastebuf_match_index_only(Main *, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t, const bool from_single, const bool, const bool)
static SlotMatchMethod get_slot_match_method(const bool from_single, const bool to_single, const KeyframePasteContext &paste_context)
static const FCurve * pastebuf_find_matching_copybuf_item(const pastebuf_match_func strategy, Main *bmain, const bAnimListElem &ale_to_paste_into, const bool from_single, const bool to_single, const KeyframePasteContext &paste_context)
bool pastebuf_match_path_full(Main *, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t, const bool from_single, const bool to_single, const bool flip)
bool pastebuf_match_path_property(Main *bmain, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t slot_handle_in_copy_buffer, const bool from_single, const bool, const bool)
std::optional< std::string > flip_names(const blender::StringRefNull rna_path)
static void do_curve_mirror_flippping(const FCurve &fcurve, BezTriple &bezt)
float wrap(float value, float max, float min)
static bool point_is_selected(PTCacheEditPoint *point)
bool RNA_property_boolean_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
int RNA_property_int_get_default(PointerRNA *ptr, PropertyRNA *prop)
float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PropertyType RNA_property_type(PropertyRNA *prop)
int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
float RNA_property_float_get_default(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_boolean_get_default(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
eKeyPasteValueOffset value_offset_mode
eKeyPasteOffset offset_mode
eAnim_Update_Flags update
Map< animrig::slot_handle_t, ID * > slot_animated_ids
Set< const FCurve * > bone_fcurves
bool is_bone(const FCurve &fcurve) const
animrig::StripKeyframeData keyframe_data
Map< animrig::slot_handle_t, std::string > slot_identifiers
bool is_single_fcurve() const
static constexpr const char * SLOTLESS_SLOT_IDENTIFIER
animrig::slot_handle_t last_used_slot_handle
animrig::Channelbag * channelbag_for_slot(StringRef slot_identifier)
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)