void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) { ID *id; bAction *action; FCurve *fcu; bool driven; bool special; fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special); if (fcu == NULL) return; if (special) { /* NLA Strip property */ if (IS_AUTOKEY_ON(scene)) { ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } else if (driven) { /* Driver - Try to insert keyframe using the driver's input as the frame, * making it easier to set up corrective drivers */ if (IS_AUTOKEY_ON(scene)) { ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } else { id = but->rnapoin.id.data; /* TODO: this should probably respect the keyingset only option for anim */ if (autokeyframe_cfra_can_key(scene, id)) { ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; short flag = ANIM_get_keyframing_flags(scene, 1); fcu->flag &= ~FCURVE_SELECTED; /* Note: We use but->rnaindex instead of fcu->array_index, * because a button may control all items of an array at once. * E.g., color wheels (see T42567). */ BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1)); insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } }
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) { ID *id; bAction *action; FCurve *fcu; bool driven; bool special; fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special); if (fcu == NULL) return; if (special) { /* NLA Strip property */ if (IS_AUTOKEY_ON(scene)) { ReportList *reports = CTX_wm_reports(C); PointerRNA ptr = {{NULL}}; PropertyRNA *prop = NULL; int index; UI_context_active_but_prop_get(C, &ptr, &prop, &index); insert_keyframe_direct(reports, ptr, prop, fcu, cfra, 0); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } else if (!driven) { id = but->rnapoin.id.data; /* TODO: this should probably respect the keyingset only option for anim */ if (autokeyframe_cfra_can_key(scene, id)) { ReportList *reports = CTX_wm_reports(C); short flag = ANIM_get_keyframing_flags(scene, 1); fcu->flag &= ~FCURVE_SELECTED; /* Note: We use but->rnaindex instead of fcu->array_index, * because a button may control all items of an array at once. * E.g., color wheels (see T42567). */ BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1)); insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, but->rnaindex, cfra, flag); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } }
static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd) { Scene *scene = CTX_data_scene(C); bAction *act; FCurve *fcu; PointerRNA ptr; PropertyRNA *prop = NULL; int nbr_gaps = 0, i; if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) return; /* gap_duration and gap_randomness are in frames, but we need seconds!!! */ gtd->gap_duration = FRA2TIME(gtd->gap_duration); gtd->gap_randomness = FRA2TIME(gtd->gap_randomness); /* Enable path! */ cu->flag |= CU_PATH; cu->pathlen = gtd->frame_range; /* Get RNA pointer to read/write path time values */ RNA_id_pointer_create((ID *)cu, &ptr); prop = RNA_struct_find_property(&ptr, "eval_time"); /* Ensure we have an F-Curve to add keyframes to */ act = verify_adt_action((ID *)cu, true); fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true); if (G.debug & G_DEBUG) { printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); } } if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) { float cfra; /* Linear extrapolation! */ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; cu->ctime = 0.0f; cfra = (float)gtd->start_frame; insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); cu->ctime = cu->pathlen; if (gtd->realtime) { cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ } else { cfra = (float)gtd->end_frame; } insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); } else { /* Use actual recorded timing! */ RNG *rng = BLI_rng_new(0); float time_range; /* CustomGaps specific */ float tot_gaps_time = 0.0f; /* Pre-process gaps, in case we don't want to keep their original timing */ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time); } if (gtd->realtime) { time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ } else { time_range = (float)(gtd->end_frame - gtd->start_frame); } if (G.debug & G_DEBUG) { printf("GP Stroke Path Conversion: Starting keying!\n"); } gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time); BLI_rng_free(rng); } /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ calchandles_fcurve(fcu); if (G.debug & G_DEBUG) { printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); } printf("\n\n"); } WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); /* send updates */ DAG_id_tag_update(&cu->id, 0); }
static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range, const int nbr_gaps, const float tot_gaps_time) { /* Use actual recorded timing! */ const float time_start = (float)gtd->start_frame; float last_valid_time = 0.0f; int end_stroke_idx = -1, start_stroke_idx = 0; float end_stroke_time = 0.0f; /* CustomGaps specific */ float delta_time = 0.0f, next_delta_time = 0.0f; int nbr_done_gaps = 0; int i; float cfra; /* This is a bit tricky, as: * - We can't add arbitrarily close points on FCurve (in time). * - We *must* have all "caps" points of all strokes in FCurve, as much as possible! */ for (i = 0; i < gtd->num_points; i++) { /* If new stroke... */ if (i > end_stroke_idx) { start_stroke_idx = i; delta_time = next_delta_time; /* find end of that new stroke */ end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps, tot_gaps_time, delta_time, &next_delta_time); /* This one should *never* be negative! */ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range); } /* Simple proportional stuff... */ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen; cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range); /* And now, the checks about timing... */ if (i == start_stroke_idx) { /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and * that the end point of the stroke is far enough! * In case it is not, we keep the end point... * Note that with CustomGaps mode, this is here we set the actual gap timing! */ if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) { if ((cfra - last_valid_time) < MIN_TIME_DELTA) { cfra = last_valid_time + MIN_TIME_DELTA; } insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); last_valid_time = cfra; } else if (G.debug & G_DEBUG) { printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx); } } else if (i == end_stroke_idx) { /* Always try to insert end point of a curve (should be safe enough, anyway...) */ if ((cfra - last_valid_time) < MIN_TIME_DELTA) { cfra = last_valid_time + MIN_TIME_DELTA; } insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); last_valid_time = cfra; } else { /* Else ("middle" point), we only insert it if it's far enough from last keyframe, * and also far enough from (not yet added!) end_stroke keyframe! */ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) { insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, INSERTKEY_FAST); last_valid_time = cfra; } else if (G.debug & G_DEBUG) { printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n", i, end_stroke_idx); } } } }