Blender V4.3
pose_slide.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
31#include "MEM_guardedalloc.h"
32
33#include "BLI_array.hh"
34#include "BLI_blenlib.h"
35#include "BLI_math_rotation.h"
36
37#include "BLT_translation.hh"
38
39#include "DNA_anim_types.h"
40#include "DNA_armature_types.h"
41#include "DNA_object_types.h"
42#include "DNA_scene_types.h"
43#include "DNA_vec_types.h"
44
45#include "BKE_fcurve.hh"
46#include "BKE_nla.hh"
47
48#include "BKE_context.hh"
49#include "BKE_layer.hh"
50#include "BKE_report.hh"
51#include "BKE_scene.hh"
52#include "BKE_unit.hh"
53
54#include "RNA_access.hh"
55#include "RNA_define.hh"
56#include "RNA_prototypes.hh"
57
58#include "WM_api.hh"
59#include "WM_types.hh"
60
61#include "UI_interface.hh"
62#include "UI_resources.hh"
63
64#include "ED_keyframes_edit.hh"
66#include "ED_markers.hh"
67#include "ED_numinput.hh"
68#include "ED_screen.hh"
69#include "ED_util.hh"
70
71#include "ANIM_fcurve.hh"
72
73#include "armature_intern.hh"
74
75using blender::Vector;
76
77/* Pixel distance from 0% to 100%. */
78#define SLIDE_PIXEL_DISTANCE (300 * U.pixelsize)
79#define OVERSHOOT_RANGE_DELTA 0.2f
80
81/* **************************************************** */
82/* A) Push & Relax, Breakdowner */
83
86 PS_LOCK_X = (1 << 0),
87 PS_LOCK_Y = (1 << 1),
88 PS_LOCK_Z = (1 << 2),
89};
90
102
105 PS_TFM_ALL = 0, /* All transforms and properties */
106
107 PS_TFM_LOC, /* Loc/Rot/Scale */
110
111 PS_TFM_BBONE_SHAPE, /* Bendy Bones */
112
113 PS_TFM_PROPS, /* Custom Properties */
114};
115
125
140
143
148
152 // short flag;
153
154 /* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */
156
161
163
166
168};
169
172 {PS_TFM_ALL,
173 "ALL",
174 0,
175 "All Properties",
176 "All properties, including transforms, bendy bone shape, and custom properties"},
177 {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
178 {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
179 {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
180 {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
181 {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
182 {0, nullptr, 0, nullptr, nullptr},
183};
184
185/* Property enum for ePoseSlide_AxisLock */
187 {0, "FREE", 0, "Free", "All axes are affected"},
188 {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
189 {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
190 {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"}, /* TODO: Combinations? */
191 {0, nullptr, 0, nullptr, nullptr},
192};
193
194/* ------------------------------------ */
195
198{
199 tPoseSlideOp *pso = MEM_new<tPoseSlideOp>(__func__);
200 op->customdata = pso;
201
202 /* Get info from context. */
203 pso->scene = CTX_data_scene(C);
204 pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */
205 pso->region = CTX_wm_region(C); /* Only really needed when doing modal(). */
206
207 pso->current_frame = pso->scene->r.cfra;
208 pso->mode = mode;
209
210 /* Set range info from property values - these may get overridden for the invoke(). */
211 pso->prev_frame = RNA_int_get(op->ptr, "prev_frame");
212 pso->next_frame = RNA_int_get(op->ptr, "next_frame");
213
214 /* Get the set of properties/axes that can be operated on. */
215 pso->channels = ePoseSlide_Channels(RNA_enum_get(op->ptr, "channels"));
216 pso->axislock = ePoseSlide_AxisLock(RNA_enum_get(op->ptr, "axis_lock"));
217
218 pso->slider = ED_slider_create(C);
219 ED_slider_factor_set(pso->slider, RNA_float_get(op->ptr, "factor"));
220
221 /* For each Pose-Channel which gets affected, get the F-Curves for that channel
222 * and set the relevant transform flags. */
224
227 pso->ob_data_array.reinitialize(objects.size());
228
229 for (const int ob_index : objects.index_range()) {
230 tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
231 Object *ob_iter = poseAnim_object_get(objects[ob_index]);
232
233 /* Ensure validity of the settings from the context. */
234 if (ob_iter == nullptr) {
235 continue;
236 }
237
238 ob_data->ob = ob_iter;
239 ob_data->valid = true;
240
241 /* Apply NLA mapping corrections so the frame look-ups work. */
243 ob_data->ob->adt, pso->prev_frame, NLATIME_CONVERT_UNMAP);
245 ob_data->ob->adt, pso->next_frame, NLATIME_CONVERT_UNMAP);
246
247 /* Set depsgraph flags. */
248 /* Make sure the lock is set OK, unlock can be accidentally saved? */
249 ob_data->ob->pose->flag |= POSE_LOCKED;
250 ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
251 }
252
253 /* Do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
254 * to the caller of this (usually only invoke() will do it, to make things more efficient). */
255 pso->keylist = ED_keylist_create();
256
257 /* Initialize numeric input. */
258 initNumInput(&pso->num);
259 pso->num.idx_max = 0; /* One axis. */
260 pso->num.unit_type[0] = B_UNIT_NONE; /* Percentages don't have any units. */
261
262 /* Return status is whether we've got all the data we were requested to get. */
263 return 1;
264}
265
270{
271 tPoseSlideOp *pso = static_cast<tPoseSlideOp *>(op->customdata);
272
273 ED_slider_destroy(C, pso->slider);
274
275 /* Hide Bone Overlay. */
276 if (pso->area) {
277 View3D *v3d = static_cast<View3D *>(pso->area->spacedata.first);
278 v3d->overlay.flag = pso->overlay_flag;
279 }
280
281 /* Free the temp pchan links and their data. */
283
284 /* Free RB-BST for keyframes (if it contained data). */
286
287 /* Free data itself. */
288 MEM_delete(pso);
289
290 /* Cleanup. */
291 op->customdata = nullptr;
292}
293
294/* ------------------------------------ */
295
300{
301 /* Wrapper around the generic version, allowing us to add some custom stuff later still. */
302 for (tPoseSlideObject &ob_data : pso->ob_data_array) {
303 if (ob_data.valid) {
304 poseAnim_mapping_refresh(C, pso->scene, ob_data.ob);
305 }
306 }
307}
308
314 Object *ob,
315 float *prev_frame,
316 float *next_frame)
317{
318 for (tPoseSlideObject &ob_data : pso->ob_data_array) {
319 Object *ob_iter = ob_data.ob;
320
321 if (ob_iter == ob) {
322 *prev_frame = ob_data.prev_frame;
323 *next_frame = ob_data.next_frame;
324 return true;
325 }
326 }
327 *prev_frame = *next_frame = 0.0f;
328 return false;
329}
330
334static void pose_slide_apply_val(tPoseSlideOp *pso, const FCurve *fcu, Object *ob, float *val)
335{
336 float prev_frame, next_frame;
337 float prev_weight, next_weight;
338 pose_frame_range_from_object_get(pso, ob, &prev_frame, &next_frame);
339
340 const float factor = ED_slider_factor_get(pso->slider);
341 const float current_frame = float(pso->current_frame);
342
343 /* Calculate the relative weights of the endpoints. */
344 if (pso->mode == POSESLIDE_BREAKDOWN) {
345 /* Get weights from the factor control. */
346 next_weight = factor;
347 prev_weight = 1.0f - next_weight;
348 }
349 else {
350 /* - these weights are derived from the relative distance of these
351 * poses from the current frame
352 * - they then get normalized so that they only sum up to 1
353 */
354
355 next_weight = current_frame - float(pso->prev_frame);
356 prev_weight = float(pso->next_frame) - current_frame;
357
358 const float total_weight = next_weight + prev_weight;
359 next_weight = (next_weight / total_weight);
360 prev_weight = (prev_weight / total_weight);
361 }
362
363 /* Get keyframe values for endpoint poses to blend with. */
364 /* Previous/start. */
365 const float prev_frame_y = evaluate_fcurve(fcu, prev_frame);
366 const float next_frame_y = evaluate_fcurve(fcu, next_frame);
367
368 /* Depending on the mode, calculate the new value. */
369 switch (pso->mode) {
370 case POSESLIDE_PUSH: /* Make the current pose more pronounced. */
371 {
372 /* Slide the pose away from the breakdown pose in the timeline */
373 (*val) -= ((prev_frame_y * prev_weight) + (next_frame_y * next_weight) - (*val)) * factor;
374 break;
375 }
376 case POSESLIDE_RELAX: /* Make the current pose more like its surrounding ones. */
377 {
378 /* Slide the pose towards the breakdown pose in the timeline */
379 (*val) += ((prev_frame_y * prev_weight) + (next_frame_y * next_weight) - (*val)) * factor;
380 break;
381 }
382 case POSESLIDE_BREAKDOWN: /* Make the current pose slide around between the endpoints. */
383 {
384 /* Perform simple linear interpolation. */
385 (*val) = interpf(next_frame_y, prev_frame_y, factor);
386 break;
387 }
388 case POSESLIDE_BLEND: /* Blend the current pose with the previous (<50%) or next key (>50%). */
389 {
390 const float current_frame_y = evaluate_fcurve(fcu, current_frame);
391 /* Convert factor to absolute 0-1 range which is needed for `interpf`. */
392 const float blend_factor = fabs((factor - 0.5f) * 2);
393
394 if (factor < 0.5) {
395 /* Blend to previous key. */
396 (*val) = interpf(prev_frame_y, current_frame_y, blend_factor);
397 }
398 else {
399 /* Blend to next key. */
400 (*val) = interpf(next_frame_y, current_frame_y, blend_factor);
401 }
402
403 break;
404 }
405 /* Those are handled in pose_slide_rest_pose_apply. */
407 break;
408 }
409 }
410}
411
416 tPChanFCurveLink *pfl,
417 float vec[3],
418 const char propName[])
419{
420 LinkData *ld = nullptr;
421 char *path = nullptr;
422
423 /* Get the path to use. */
424 path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
425
426 /* Using this path, find each matching F-Curve for the variables we're interested in. */
427 while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
428 FCurve *fcu = (FCurve *)ld->data;
429 const int idx = fcu->array_index;
430 const int lock = pso->axislock;
431
432 /* Check if this F-Curve is ok given the current axis locks. */
433 BLI_assert(fcu->array_index < 3);
434
435 if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
436 ((lock & PS_LOCK_Z) && (idx == 2)))
437 {
438 /* Just work on these channels one by one... there's no interaction between values. */
439 pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
440 }
441 }
442
443 /* Free the temp path we got. */
444 MEM_freeN(path);
445}
446
451 tPChanFCurveLink *pfl,
452 const char prop_prefix[])
453{
454 int len = strlen(pfl->pchan_path);
455
456 /* Setup pointer RNA for resolving paths. */
457 PointerRNA ptr = RNA_pointer_create(nullptr, &RNA_PoseBone, pfl->pchan);
458
459 /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
460 * so just check for opening pair after the end of the path
461 * - bbone properties are similar, but they always start with a prefix "bbone_*",
462 * so a similar method should work here for those too
463 */
464 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
465 FCurve *fcu = (FCurve *)ld->data;
466 const char *bPtr, *pPtr;
467
468 if (fcu->rna_path == nullptr) {
469 continue;
470 }
471
472 /* Do we have a match?
473 * - bPtr is the RNA Path with the standard part chopped off.
474 * - pPtr is the chunk of the path which is left over.
475 */
476 bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
477 pPtr = strstr(bPtr, prop_prefix);
478
479 if (pPtr) {
480 /* Use RNA to try and get a handle on this property, then, assuming that it is just
481 * numerical, try and grab the value as a float for temp editing before setting back. */
483
484 if (prop) {
485 switch (RNA_property_type(prop)) {
486 /* Continuous values that can be smoothly interpolated. */
487 case PROP_FLOAT: {
488 const bool is_array = RNA_property_array_check(prop);
489 float tval;
490 if (is_array) {
491 if (UNLIKELY(uint(fcu->array_index) >= RNA_property_array_length(&ptr, prop))) {
492 break; /* Out of range, skip. */
493 }
494 tval = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
495 }
496 else {
497 tval = RNA_property_float_get(&ptr, prop);
498 }
499
500 pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
501
502 if (is_array) {
503 RNA_property_float_set_index(&ptr, prop, fcu->array_index, tval);
504 }
505 else {
506 RNA_property_float_set(&ptr, prop, tval);
507 }
508 break;
509 }
510 case PROP_INT: {
511 const bool is_array = RNA_property_array_check(prop);
512 float tval;
513 if (is_array) {
514 if (UNLIKELY(uint(fcu->array_index) >= RNA_property_array_length(&ptr, prop))) {
515 break; /* Out of range, skip. */
516 }
517 tval = RNA_property_int_get_index(&ptr, prop, fcu->array_index);
518 }
519 else {
520 tval = RNA_property_int_get(&ptr, prop);
521 }
522
523 pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
524
525 if (is_array) {
526 RNA_property_int_set_index(&ptr, prop, fcu->array_index, tval);
527 }
528 else {
529 RNA_property_int_set(&ptr, prop, tval);
530 }
531 break;
532 }
533
534 /* Values which can only take discrete values. */
535 case PROP_BOOLEAN: {
536 const bool is_array = RNA_property_array_check(prop);
537 float tval;
538 if (is_array) {
539 if (UNLIKELY(uint(fcu->array_index) >= RNA_property_array_length(&ptr, prop))) {
540 break; /* Out of range, skip. */
541 }
543 }
544 else {
545 tval = float(RNA_property_boolean_get(&ptr, prop));
546 }
547
548 pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
549
550 /* XXX: do we need threshold clamping here? */
551 if (is_array) {
553 }
554 else {
555 RNA_property_boolean_set(&ptr, prop, tval);
556 }
557 break;
558 }
559 case PROP_ENUM: {
560 /* Don't handle this case - these don't usually represent interchangeable
561 * set of values which should be interpolated between. */
562 break;
563 }
564
565 default:
566 /* Cannot handle. */
567 // printf("Cannot Pose Slide non-numerical property\n");
568 break;
569 }
570 }
571 }
572 }
573}
574
579{
580 const FCurve *fcu_w = nullptr, *fcu_x = nullptr, *fcu_y = nullptr, *fcu_z = nullptr;
581 bPoseChannel *pchan = pfl->pchan;
582 LinkData *ld = nullptr;
583 char *path = nullptr;
584 float prev_frame, next_frame;
585
586 if (!pose_frame_range_from_object_get(pso, pfl->ob, &prev_frame, &next_frame)) {
587 BLI_assert_msg(0, "Invalid pfl data");
588 return;
589 }
590
591 /* Get the path to use - this should be quaternion rotations only (needs care). */
592 path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
593
594 /* Get the current frame number. */
595 const float current_frame = float(pso->current_frame);
596 const float factor = ED_slider_factor_get(pso->slider);
597
598 /* Using this path, find each matching F-Curve for the variables we're interested in. */
599 while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
600 FCurve *fcu = (FCurve *)ld->data;
601
602 /* Assign this F-Curve to one of the relevant pointers. */
603 switch (fcu->array_index) {
604 case 3: /* z */
605 fcu_z = fcu;
606 break;
607 case 2: /* y */
608 fcu_y = fcu;
609 break;
610 case 1: /* x */
611 fcu_x = fcu;
612 break;
613 case 0: /* w */
614 fcu_w = fcu;
615 break;
616 }
617 }
618
619 /* Only if all channels exist, proceed. */
620 if (fcu_w && fcu_x && fcu_y && fcu_z) {
621 float quat_final[4];
622
623 /* Perform blending. */
625 float quat_prev[4], quat_next[4];
626
627 quat_prev[0] = evaluate_fcurve(fcu_w, prev_frame);
628 quat_prev[1] = evaluate_fcurve(fcu_x, prev_frame);
629 quat_prev[2] = evaluate_fcurve(fcu_y, prev_frame);
630 quat_prev[3] = evaluate_fcurve(fcu_z, prev_frame);
631
632 quat_next[0] = evaluate_fcurve(fcu_w, next_frame);
633 quat_next[1] = evaluate_fcurve(fcu_x, next_frame);
634 quat_next[2] = evaluate_fcurve(fcu_y, next_frame);
635 quat_next[3] = evaluate_fcurve(fcu_z, next_frame);
636
637 normalize_qt(quat_prev);
638 normalize_qt(quat_next);
639
640 if (pso->mode == POSESLIDE_BREAKDOWN) {
641 /* Just perform the interpolation between quat_prev and
642 * quat_next using pso->factor as a guide. */
643 interp_qt_qtqt(quat_final, quat_prev, quat_next, factor);
644 }
645 else {
646 float quat_curr[4], quat_breakdown[4];
647
648 normalize_qt_qt(quat_curr, pchan->quat);
649
650 /* Compute breakdown based on actual frame range. */
651 const float interp_factor = (current_frame - pso->prev_frame) /
652 float(pso->next_frame - pso->prev_frame);
653
654 interp_qt_qtqt(quat_breakdown, quat_prev, quat_next, interp_factor);
655
656 if (pso->mode == POSESLIDE_PUSH) {
657 interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + factor);
658 }
659 else {
661 interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, factor);
662 }
663 }
664 }
665 else if (pso->mode == POSESLIDE_BLEND) {
666 float quat_blend[4];
667 float quat_curr[4];
668
669 copy_qt_qt(quat_curr, pchan->quat);
670
671 if (factor < 0.5) {
672 quat_blend[0] = evaluate_fcurve(fcu_w, prev_frame);
673 quat_blend[1] = evaluate_fcurve(fcu_x, prev_frame);
674 quat_blend[2] = evaluate_fcurve(fcu_y, prev_frame);
675 quat_blend[3] = evaluate_fcurve(fcu_z, prev_frame);
676 }
677 else {
678 quat_blend[0] = evaluate_fcurve(fcu_w, next_frame);
679 quat_blend[1] = evaluate_fcurve(fcu_x, next_frame);
680 quat_blend[2] = evaluate_fcurve(fcu_y, next_frame);
681 quat_blend[3] = evaluate_fcurve(fcu_z, next_frame);
682 }
683
684 normalize_qt(quat_blend);
685 normalize_qt(quat_curr);
686
687 const float blend_factor = fabs((factor - 0.5f) * 2);
688
689 interp_qt_qtqt(quat_final, quat_curr, quat_blend, blend_factor);
690 }
691
692 /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
693 quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
694 }
695
696 /* Free the path now. */
697 MEM_freeN(path);
698}
699
700static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value)
701{
702 /* We only slide to the rest pose. So only use the default rest pose value. */
703 const int lock = pso->axislock;
704 const float factor = ED_slider_factor_get(pso->slider);
705 for (int idx = 0; idx < 3; idx++) {
706 if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
707 ((lock & PS_LOCK_Z) && (idx == 2)))
708 {
709 float diff_val = default_value - vec[idx];
710 vec[idx] += factor * diff_val;
711 }
712 }
713}
714
715static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat)
716{
717 /* We only slide to the rest pose. So only use the default rest pose value. */
718 float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f};
719 if (!quat) {
720 /* Axis Angle */
721 default_values[0] = 0.0f;
722 default_values[2] = 1.0f;
723 }
724 const float factor = ED_slider_factor_get(pso->slider);
725 for (int idx = 0; idx < 4; idx++) {
726 float diff_val = default_values[idx] - vec[idx];
727 vec[idx] += factor * diff_val;
728 }
729}
730
735{
736 /* For each link, handle each set of transforms. */
738 /* Valid transforms for each #bPoseChannel should have been noted already.
739 * - Sliding the pose should be a straightforward exercise for location+rotation,
740 * but rotations get more complicated since we may want to use quaternion blending
741 * for quaternions instead.
742 */
743 bPoseChannel *pchan = pfl->pchan;
744
745 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
746 /* Calculate these for the 'location' vector, and use location curves. */
747 pose_slide_rest_pose_apply_vec3(pso, pchan->loc, 0.0f);
748 }
749
750 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
751 /* Calculate these for the 'scale' vector, and use scale curves. */
752 pose_slide_rest_pose_apply_vec3(pso, pchan->size, 1.0f);
753 }
754
755 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
756 /* Everything depends on the rotation mode. */
757 if (pchan->rotmode > 0) {
758 /* Eulers - so calculate these for the 'eul' vector, and use euler_rotation curves. */
759 pose_slide_rest_pose_apply_vec3(pso, pchan->eul, 0.0f);
760 }
761 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
762 pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, false);
763 }
764 else {
765 /* Quaternions - use quaternion blending. */
767 }
768 }
769
771 /* Bbone properties - they all start a "bbone_" prefix. */
772 /* TODO: Not implemented. */
773 // pose_slide_apply_props(pso, pfl, "bbone_");
774 }
775
776 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
777 /* Not strictly a transform, but custom properties contribute
778 * to the pose produced in many rigs (e.g. the facial rigs used in Sintel). */
779 /* TODO: Not implemented. */
780 // pose_slide_apply_props(pso, pfl, "[\"");
781 }
782 }
783
784 /* Depsgraph updates + redraws. */
785 pose_slide_refresh(C, pso);
786}
787
792{
793 /* Sanitize the frame ranges. */
794 if (pso->prev_frame == pso->next_frame) {
795 /* Move out one step either side. */
796 pso->prev_frame--;
797 pso->next_frame++;
798
799 for (tPoseSlideObject &ob_data : pso->ob_data_array) {
800 if (!ob_data.valid) {
801 continue;
802 }
803
804 /* Apply NLA mapping corrections so the frame look-ups work. */
805 ob_data.prev_frame = BKE_nla_tweakedit_remap(
806 ob_data.ob->adt, pso->prev_frame, NLATIME_CONVERT_UNMAP);
807 ob_data.next_frame = BKE_nla_tweakedit_remap(
808 ob_data.ob->adt, pso->next_frame, NLATIME_CONVERT_UNMAP);
809 }
810 }
811
812 /* For each link, handle each set of transforms. */
814 /* Valid transforms for each #bPoseChannel should have been noted already
815 * - sliding the pose should be a straightforward exercise for location+rotation,
816 * but rotations get more complicated since we may want to use quaternion blending
817 * for quaternions instead...
818 */
819 bPoseChannel *pchan = pfl->pchan;
820
821 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
822 /* Calculate these for the 'location' vector, and use location curves. */
823 pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
824 }
825
826 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
827 /* Calculate these for the 'scale' vector, and use scale curves. */
828 pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
829 }
830
831 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
832 /* Everything depends on the rotation mode. */
833 if (pchan->rotmode > 0) {
834 /* Eulers - so calculate these for the 'eul' vector, and use euler_rotation curves. */
835 pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
836 }
837 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
838 /* TODO: need to figure out how to do this! */
839 }
840 else {
841 /* Quaternions - use quaternion blending. */
842 pose_slide_apply_quat(pso, pfl);
843 }
844 }
845
847 /* Bbone properties - they all start a "bbone_" prefix. */
848 pose_slide_apply_props(pso, pfl, "bbone_");
849 }
850
851 if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
852 /* Not strictly a transform, but custom properties contribute
853 * to the pose produced in many rigs (e.g. the facial rigs used in Sintel). */
854 pose_slide_apply_props(pso, pfl, "[\"");
855 }
856 }
857
858 /* Depsgraph updates + redraws. */
859 pose_slide_refresh(C, pso);
860}
861
866{
867 /* Wrapper around the generic call. */
868 poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, float(pso->current_frame));
869}
870
875{
876 /* Wrapper around the generic call, so that custom stuff can be added later. */
878}
879
880/* ------------------------------------ */
881
888{
889 char status_str[UI_MAX_DRAW_STR];
890 char limits_str[UI_MAX_DRAW_STR];
891 char axis_str[50];
892 char mode_str[32];
893 char slider_str[UI_MAX_DRAW_STR];
894 char bone_vis_str[50];
895
896 switch (pso->mode) {
897 case POSESLIDE_PUSH:
898 STRNCPY(mode_str, IFACE_("Push Pose"));
899 break;
900 case POSESLIDE_RELAX:
901 STRNCPY(mode_str, IFACE_("Relax Pose"));
902 break;
904 STRNCPY(mode_str, IFACE_("Breakdown"));
905 break;
906 case POSESLIDE_BLEND:
907 STRNCPY(mode_str, IFACE_("Blend to Neighbor"));
908 break;
909
910 default:
911 /* Unknown. */
912 STRNCPY(mode_str, IFACE_("Sliding-Tool"));
913 break;
914 }
915
916 switch (pso->axislock) {
917 case PS_LOCK_X:
918 STRNCPY(axis_str, IFACE_("[X]/Y/Z axis only (X to clear)"));
919 break;
920 case PS_LOCK_Y:
921 STRNCPY(axis_str, IFACE_("X/[Y]/Z axis only (Y to clear)"));
922 break;
923 case PS_LOCK_Z:
924 STRNCPY(axis_str, IFACE_("X/Y/[Z] axis only (Z to clear)"));
925 break;
926
927 default:
929 STRNCPY(axis_str, IFACE_("X/Y/Z = Axis Constraint"));
930 }
931 else {
932 axis_str[0] = '\0';
933 }
934 break;
935 }
936
937 switch (pso->channels) {
938 case PS_TFM_LOC:
939 SNPRINTF(limits_str, IFACE_("[G]/R/S/B/C - Location only (G to clear) | %s"), axis_str);
940 break;
941 case PS_TFM_ROT:
942 SNPRINTF(limits_str, IFACE_("G/[R]/S/B/C - Rotation only (R to clear) | %s"), axis_str);
943 break;
944 case PS_TFM_SIZE:
945 SNPRINTF(limits_str, IFACE_("G/R/[S]/B/C - Scale only (S to clear) | %s"), axis_str);
946 break;
948 STRNCPY(limits_str, IFACE_("G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s"));
949 break;
950 case PS_TFM_PROPS:
951 STRNCPY(limits_str, IFACE_("G/R/S/B/[C] - Custom Properties only (C to clear) | %s"));
952 break;
953 default:
954 STRNCPY(limits_str, IFACE_("G/R/S/B/C - Limit to Transform/Property Set"));
955 break;
956 }
957
958 STRNCPY(bone_vis_str, IFACE_("[H] - Toggle bone visibility"));
959
960 ED_slider_status_string_get(pso->slider, slider_str, sizeof(slider_str));
961
962 if (hasNumInput(&pso->num)) {
963 Scene *scene = pso->scene;
964 char str_offs[NUM_STR_REP_LEN];
965
966 outputNumInput(&pso->num, str_offs, &scene->unit);
967
968 SNPRINTF(status_str, "%s: %s | %s", mode_str, str_offs, limits_str);
969 }
970 else {
971 SNPRINTF(status_str, "%s: %s | %s | %s", mode_str, limits_str, slider_str, bone_vis_str);
972 }
973
974 ED_workspace_status_text(C, status_str);
975 ED_area_status_text(pso->area, "");
976}
977
981static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *event)
982{
983 wmWindow *win = CTX_wm_window(C);
984
985 tPoseSlideOp *pso = static_cast<tPoseSlideOp *>(op->customdata);
986
987 ED_slider_init(pso->slider, event);
988
989 /* For each link, add all its keyframes to the search tree. */
991 /* Do this for each F-Curve. */
992 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
993 FCurve *fcu = (FCurve *)ld->data;
994 fcurve_to_keylist(pfl->ob->adt, fcu, pso->keylist, 0, {-FLT_MAX, FLT_MAX});
995 }
996 }
997
998 /* Cancel if no keyframes found. */
1000 if (ED_keylist_is_empty(pso->keylist)) {
1001 BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
1002 pose_slide_exit(C, op);
1003 return OPERATOR_CANCELLED;
1004 }
1005
1006 float current_frame = float(pso->current_frame);
1007
1008 /* Firstly, check if the current frame is a keyframe. */
1009 const ActKeyColumn *ak = ED_keylist_find_exact(pso->keylist, current_frame);
1010
1011 if (ak == nullptr) {
1012 /* Current frame is not a keyframe, so search. */
1013 const ActKeyColumn *pk = ED_keylist_find_prev(pso->keylist, current_frame);
1014 const ActKeyColumn *nk = ED_keylist_find_next(pso->keylist, current_frame);
1015
1016 /* New set the frames. */
1017 /* Previous frame. */
1018 pso->prev_frame = (pk) ? (pk->cfra) : (pso->current_frame - 1);
1019 RNA_int_set(op->ptr, "prev_frame", pso->prev_frame);
1020 /* Next frame. */
1021 pso->next_frame = (nk) ? (nk->cfra) : (pso->current_frame + 1);
1022 RNA_int_set(op->ptr, "next_frame", pso->next_frame);
1023 }
1024 else {
1025 /* Current frame itself is a keyframe, so just take keyframes on either side. */
1026 /* Previous frame. */
1027 pso->prev_frame = (ak->prev) ? (ak->prev->cfra) : (pso->current_frame - 1);
1028 RNA_int_set(op->ptr, "prev_frame", pso->prev_frame);
1029 /* Next frame. */
1030 pso->next_frame = (ak->next) ? (ak->next->cfra) : (pso->current_frame + 1);
1031 RNA_int_set(op->ptr, "next_frame", pso->next_frame);
1032 }
1033
1034 /* Apply NLA mapping corrections so the frame look-ups work. */
1035 for (tPoseSlideObject &ob_data : pso->ob_data_array) {
1036 if (ob_data.valid) {
1037 ob_data.prev_frame = BKE_nla_tweakedit_remap(
1038 ob_data.ob->adt, pso->prev_frame, NLATIME_CONVERT_UNMAP);
1039 ob_data.next_frame = BKE_nla_tweakedit_remap(
1040 ob_data.ob->adt, pso->next_frame, NLATIME_CONVERT_UNMAP);
1041 }
1042 }
1043
1044 /* Initial apply for operator. */
1045 /* TODO: need to calculate factor for initial round too. */
1046 if (!ELEM(pso->mode, POSESLIDE_BLEND_REST)) {
1047 pose_slide_apply(C, pso);
1048 }
1049 else {
1051 }
1052
1053 /* Depsgraph updates + redraws. */
1054 pose_slide_refresh(C, pso);
1055
1056 /* Set cursor to indicate modal. */
1058
1059 /* Header print. */
1060 pose_slide_draw_status(C, pso);
1061
1062 /* Add a modal handler for this operator. */
1064
1065 /* Save current bone visibility. */
1066 View3D *v3d = static_cast<View3D *>(pso->area->spacedata.first);
1067 pso->overlay_flag = v3d->overlay.flag;
1068
1070}
1071
1076 tPoseSlideOp *pso,
1077 ePoseSlide_Channels channel)
1078{
1079 /* Turn channel on or off? */
1080 if (pso->channels == channel) {
1081 /* Already limiting to transform only, so pressing this again turns it off */
1082 pso->channels = PS_TFM_ALL;
1083 }
1084 else {
1085 /* Only this set of channels */
1086 pso->channels = channel;
1087 }
1088 RNA_enum_set(op->ptr, "channels", pso->channels);
1089
1090 /* Reset axis limits too for good measure */
1091 pso->axislock = ePoseSlide_AxisLock(0);
1092 RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
1093}
1094
1099 tPoseSlideOp *pso,
1101{
1102 /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
1104 pso->axislock = ePoseSlide_AxisLock(0);
1105 RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
1106 return false;
1107 }
1108
1109 /* Turn on or off? */
1110 if (pso->axislock == axis) {
1111 /* Already limiting on this axis, so turn off */
1112 pso->axislock = ePoseSlide_AxisLock(0);
1113 }
1114 else {
1115 /* Only this axis */
1116 pso->axislock = axis;
1117 }
1118 RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
1119
1120 /* Setting changed, so pose update is needed */
1121 return true;
1122}
1123
1127static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
1128{
1129 tPoseSlideOp *pso = static_cast<tPoseSlideOp *>(op->customdata);
1130 wmWindow *win = CTX_wm_window(C);
1131 bool do_pose_update = false;
1132
1133 const bool has_numinput = hasNumInput(&pso->num);
1134
1135 do_pose_update = ED_slider_modal(pso->slider, event);
1136
1137 switch (event->type) {
1138 case LEFTMOUSE: /* Confirm. */
1139 case EVT_RETKEY:
1140 case EVT_PADENTER: {
1141 if (event->val == KM_PRESS) {
1142 /* Return to normal cursor and header status. */
1143 ED_workspace_status_text(C, nullptr);
1144 ED_area_status_text(pso->area, nullptr);
1146
1147 /* Depsgraph updates + redraws. Redraw needed to remove UI. */
1148 pose_slide_refresh(C, pso);
1149
1150 /* Insert keyframes as required. */
1152 pose_slide_exit(C, op);
1153
1154 /* Done! */
1155 return OPERATOR_FINISHED;
1156 }
1157 break;
1158 }
1159
1160 case EVT_ESCKEY: /* Cancel. */
1161 case RIGHTMOUSE: {
1162 if (event->val == KM_PRESS) {
1163 /* Return to normal cursor and header status. */
1164 ED_workspace_status_text(C, nullptr);
1165 ED_area_status_text(pso->area, nullptr);
1167
1168 /* Reset transforms back to original state. */
1169 pose_slide_reset(pso);
1170
1171 /* Depsgraph updates + redraws. */
1172 pose_slide_refresh(C, pso);
1173
1174 /* Clean up temp data. */
1175 pose_slide_exit(C, op);
1176
1177 /* Canceled! */
1178 return OPERATOR_CANCELLED;
1179 }
1180 break;
1181 }
1182
1183 /* Factor Change... */
1184 case MOUSEMOVE: /* Calculate new position. */
1185 {
1186 /* Only handle mouse-move if not doing numinput. */
1187 if (has_numinput == false) {
1188 /* Update pose to reflect the new values (see below). */
1189 do_pose_update = true;
1190 }
1191 break;
1192 }
1193 default: {
1194 if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
1195 float value;
1196
1197 /* Grab percentage from numeric input, and store this new value for redo
1198 * NOTE: users see ints, while internally we use a 0-1 float
1199 */
1200 value = ED_slider_factor_get(pso->slider) * 100.0f;
1201 applyNumInput(&pso->num, &value);
1202
1203 float factor = value / 100;
1204 ED_slider_factor_set(pso->slider, factor);
1205 RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider));
1206
1207 /* Update pose to reflect the new values (see below) */
1208 do_pose_update = true;
1209 break;
1210 }
1211 if (event->val == KM_PRESS) {
1212 switch (event->type) {
1213 /* Transform Channel Limits. */
1214 /* XXX: Replace these hard-coded hotkeys with a modal-map that can be customized. */
1215 case EVT_GKEY: /* Location */
1216 {
1218 do_pose_update = true;
1219 break;
1220 }
1221 case EVT_RKEY: /* Rotation */
1222 {
1224 do_pose_update = true;
1225 break;
1226 }
1227 case EVT_SKEY: /* Scale */
1228 {
1230 do_pose_update = true;
1231 break;
1232 }
1233 case EVT_BKEY: /* Bendy Bones */
1234 {
1236 do_pose_update = true;
1237 break;
1238 }
1239 case EVT_CKEY: /* Custom Properties */
1240 {
1242 do_pose_update = true;
1243 break;
1244 }
1245
1246 /* Axis Locks */
1247 /* XXX: Hardcoded... */
1248 case EVT_XKEY: {
1250 do_pose_update = true;
1251 }
1252 break;
1253 }
1254 case EVT_YKEY: {
1256 do_pose_update = true;
1257 }
1258 break;
1259 }
1260 case EVT_ZKEY: {
1262 do_pose_update = true;
1263 }
1264 break;
1265 }
1266
1267 /* Toggle Bone visibility. */
1268 case EVT_HKEY: {
1269 View3D *v3d = static_cast<View3D *>(pso->area->spacedata.first);
1272 }
1273
1274 default: /* Some other unhandled key... */
1275 break;
1276 }
1277 }
1278 else {
1279 /* Unhandled event - maybe it was some view manipulation? */
1280 /* Allow to pass through. */
1282 }
1283 }
1284 }
1285
1286 /* Perform pose updates - in response to some user action
1287 * (e.g. pressing a key or moving the mouse). */
1288 if (do_pose_update) {
1289 RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider));
1290
1291 /* Update percentage indicator in header. */
1292 pose_slide_draw_status(C, pso);
1293
1294 /* Reset transforms (to avoid accumulation errors). */
1295 pose_slide_reset(pso);
1296
1297 /* Apply. */
1298 if (!ELEM(pso->mode, POSESLIDE_BLEND_REST)) {
1299 pose_slide_apply(C, pso);
1300 }
1301 else {
1303 }
1304 }
1305
1306 /* Still running. */
1308}
1309
1314{
1315 /* Cleanup and done. */
1316 pose_slide_exit(C, op);
1317}
1318
1323{
1324 /* Settings should have been set up ok for applying, so just apply! */
1325 if (!ELEM(pso->mode, POSESLIDE_BLEND_REST)) {
1326 pose_slide_apply(C, pso);
1327 }
1328 else {
1330 }
1331
1332 /* Insert keyframes if needed. */
1334
1335 /* Cleanup and done. */
1336 pose_slide_exit(C, op);
1337
1338 return OPERATOR_FINISHED;
1339}
1340
1345{
1346 PropertyRNA *prop;
1347
1349 "factor",
1350 0.5f,
1351 0.0f,
1352 1.0f,
1353 "Factor",
1354 "Weighting factor for which keyframe is favored more",
1355 0.0,
1356 1.0);
1358
1359 prop = RNA_def_int(ot->srna,
1360 "prev_frame",
1361 0,
1362 MINAFRAME,
1363 MAXFRAME,
1364 "Previous Keyframe",
1365 "Frame number of keyframe immediately before the current frame",
1366 0,
1367 50);
1369
1370 prop = RNA_def_int(ot->srna,
1371 "next_frame",
1372 0,
1373 MINAFRAME,
1374 MAXFRAME,
1375 "Next Keyframe",
1376 "Frame number of keyframe immediately after the current frame",
1377 0,
1378 50);
1380
1381 prop = RNA_def_enum(ot->srna,
1382 "channels",
1384 PS_TFM_ALL,
1385 "Channels",
1386 "Set of properties that are affected");
1388 prop = RNA_def_enum(ot->srna,
1389 "axis_lock",
1391 0,
1392 "Axis Lock",
1393 "Transform axis to restrict effects to");
1395}
1396
1397/* ------------------------------------ */
1398
1402static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1403{
1404 /* Initialize data. */
1405 if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
1406 pose_slide_exit(C, op);
1407 return OPERATOR_CANCELLED;
1408 }
1409
1410 /* Do common setup work. */
1411 return pose_slide_invoke_common(C, op, event);
1412}
1413
1418{
1419 tPoseSlideOp *pso;
1420
1421 /* Initialize data (from RNA-props). */
1422 if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
1423 pose_slide_exit(C, op);
1424 return OPERATOR_CANCELLED;
1425 }
1426
1427 pso = static_cast<tPoseSlideOp *>(op->customdata);
1428
1429 /* Do common exec work. */
1430 return pose_slide_exec_common(C, op, pso);
1431}
1432
1434{
1435 /* identifiers */
1436 ot->name = "Push Pose from Breakdown";
1437 ot->idname = "POSE_OT_push";
1438 ot->description = "Exaggerate the current pose in regards to the breakdown pose";
1439
1440 /* callbacks */
1446
1447 /* flags */
1449
1450 /* Properties */
1452}
1453
1454/* ........................ */
1455
1459static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1460{
1461 /* Initialize data. */
1462 if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
1463 pose_slide_exit(C, op);
1464 return OPERATOR_CANCELLED;
1465 }
1466
1467 /* Do common setup work. */
1468 return pose_slide_invoke_common(C, op, event);
1469}
1470
1475{
1476 tPoseSlideOp *pso;
1477
1478 /* Initialize data (from RNA-props). */
1479 if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
1480 pose_slide_exit(C, op);
1481 return OPERATOR_CANCELLED;
1482 }
1483
1484 pso = static_cast<tPoseSlideOp *>(op->customdata);
1485
1486 /* Do common exec work. */
1487 return pose_slide_exec_common(C, op, pso);
1488}
1489
1491{
1492 /* identifiers */
1493 ot->name = "Relax Pose to Breakdown";
1494 ot->idname = "POSE_OT_relax";
1495 ot->description = "Make the current pose more similar to its breakdown pose";
1496
1497 /* callbacks */
1503
1504 /* flags */
1506
1507 /* Properties */
1509}
1510
1511/* ........................ */
1516{
1517 /* Initialize data. */
1518 if (pose_slide_init(C, op, POSESLIDE_BLEND_REST) == 0) {
1519 pose_slide_exit(C, op);
1520 return OPERATOR_CANCELLED;
1521 }
1522
1523 tPoseSlideOp *pso = static_cast<tPoseSlideOp *>(op->customdata);
1526
1527 /* do common setup work */
1528 return pose_slide_invoke_common(C, op, event);
1529}
1530
1535{
1536 tPoseSlideOp *pso;
1537
1538 /* Initialize data (from RNA-props). */
1539 if (pose_slide_init(C, op, POSESLIDE_BLEND_REST) == 0) {
1540 pose_slide_exit(C, op);
1541 return OPERATOR_CANCELLED;
1542 }
1543
1544 pso = static_cast<tPoseSlideOp *>(op->customdata);
1545
1546 /* Do common exec work. */
1547 return pose_slide_exec_common(C, op, pso);
1548}
1549
1551{
1552 /* identifiers */
1553 ot->name = "Blend Pose with Rest Pose";
1554 ot->idname = "POSE_OT_blend_with_rest";
1555 ot->description = "Make the current pose more similar to, or further away from, the rest pose";
1556
1557 /* callbacks */
1563
1564 /* flags */
1566
1567 /* Properties */
1569}
1570
1571/* ........................ */
1572
1577{
1578 /* Initialize data. */
1579 if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
1580 pose_slide_exit(C, op);
1581 return OPERATOR_CANCELLED;
1582 }
1583
1584 /* Do common setup work. */
1585 return pose_slide_invoke_common(C, op, event);
1586}
1587
1592{
1593 tPoseSlideOp *pso;
1594
1595 /* Initialize data (from RNA-props). */
1596 if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
1597 pose_slide_exit(C, op);
1598 return OPERATOR_CANCELLED;
1599 }
1600
1601 pso = static_cast<tPoseSlideOp *>(op->customdata);
1602
1603 /* Do common exec work. */
1604 return pose_slide_exec_common(C, op, pso);
1605}
1606
1608{
1609 /* identifiers */
1610 ot->name = "Pose Breakdowner";
1611 ot->idname = "POSE_OT_breakdown";
1612 ot->description = "Create a suitable breakdown pose on the current frame";
1613
1614 /* callbacks */
1620
1621 /* flags */
1623
1624 /* Properties */
1626}
1627
1628/* ........................ */
1630{
1631 /* Initialize data. */
1632 if (pose_slide_init(C, op, POSESLIDE_BLEND) == 0) {
1633 pose_slide_exit(C, op);
1634 return OPERATOR_CANCELLED;
1635 }
1636
1637 /* Do common setup work. */
1638 return pose_slide_invoke_common(C, op, event);
1639}
1640
1642{
1643 tPoseSlideOp *pso;
1644
1645 /* Initialize data (from RNA-props). */
1646 if (pose_slide_init(C, op, POSESLIDE_BLEND) == 0) {
1647 pose_slide_exit(C, op);
1648 return OPERATOR_CANCELLED;
1649 }
1650
1651 pso = static_cast<tPoseSlideOp *>(op->customdata);
1652
1653 /* Do common exec work. */
1654 return pose_slide_exec_common(C, op, pso);
1655}
1656
1658{
1659 /* Identifiers. */
1660 ot->name = "Blend to Neighbor";
1661 ot->idname = "POSE_OT_blend_to_neighbor";
1662 ot->description = "Blend from current position to previous or next keyframe";
1663
1664 /* Callbacks. */
1670
1671 /* Flags. */
1673
1674 /* Properties. */
1676}
1677
1678/* **************************************************** */
1679/* B) Pose Propagate */
1680
1681/* "termination conditions" - i.e. when we stop */
1697
1698/* --------------------------------- */
1699
1702 float frame;
1703};
1704
1705static void propagate_curve_values(ListBase /*tPChanFCurveLink*/ *pflinks,
1706 const float source_frame,
1707 ListBase /*FrameLink*/ *target_frames)
1708{
1709 using namespace blender::animrig;
1710 const KeyframeSettings settings = get_keyframe_settings(true);
1711 LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) {
1712 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
1713 FCurve *fcu = (FCurve *)ld->data;
1714 if (!fcu->bezt) {
1715 continue;
1716 }
1717 const float current_fcu_value = evaluate_fcurve(fcu, source_frame);
1718 LISTBASE_FOREACH (FrameLink *, target_frame, target_frames) {
1719 insert_vert_fcurve(
1720 fcu, {target_frame->frame, current_fcu_value}, settings, INSERTKEY_NOFLAGS);
1721 }
1722 }
1723 }
1724}
1725
1726static float find_next_key(ListBase *pflinks, const float start_frame)
1727{
1728 float target_frame = FLT_MAX;
1729 LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) {
1730 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
1731 FCurve *fcu = (FCurve *)ld->data;
1732 if (!fcu->bezt) {
1733 continue;
1734 }
1735 bool replace;
1736 int current_frame_index = BKE_fcurve_bezt_binarysearch_index(
1737 fcu->bezt, start_frame, fcu->totvert, &replace);
1738 if (replace) {
1739 current_frame_index += 1;
1740 }
1741 const int bezt_index = min_ii(current_frame_index, fcu->totvert - 1);
1742 target_frame = min_ff(target_frame, fcu->bezt[bezt_index].vec[1][0]);
1743 }
1744 }
1745
1746 return target_frame;
1747}
1748
1749static float find_last_key(ListBase *pflinks)
1750{
1751 float target_frame = FLT_MIN;
1752 LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) {
1753 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
1754 const FCurve *fcu = (const FCurve *)ld->data;
1755 if (!fcu->bezt) {
1756 continue;
1757 }
1758 target_frame = max_ff(target_frame, fcu->bezt[fcu->totvert - 1].vec[1][0]);
1759 }
1760 }
1761
1762 return target_frame;
1763}
1764
1765static void get_selected_marker_positions(Scene *scene, ListBase /*FrameLink*/ *target_frames)
1766{
1767 ListBase selected_markers = {nullptr, nullptr};
1768 ED_markers_make_cfra_list(&scene->markers, &selected_markers, true);
1769 LISTBASE_FOREACH (CfraElem *, marker, &selected_markers) {
1770 FrameLink *link = static_cast<FrameLink *>(MEM_callocN(sizeof(FrameLink), "Marker Key Link"));
1771 link->frame = marker->cfra;
1772 BLI_addtail(target_frames, link);
1773 }
1774 BLI_freelistN(&selected_markers);
1775}
1776
1778 const float start_frame,
1779 const float end_frame,
1780 ListBase /*FrameLink*/ *target_frames)
1781{
1782 AnimKeylist *keylist = ED_keylist_create();
1783 LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) {
1784 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
1785 FCurve *fcu = (FCurve *)ld->data;
1786 fcurve_to_keylist(nullptr, fcu, keylist, 0, {start_frame, end_frame});
1787 }
1788 }
1789 LISTBASE_FOREACH (ActKeyColumn *, column, ED_keylist_listbase(keylist)) {
1790 if (column->cfra <= start_frame) {
1791 continue;
1792 }
1793 if (column->cfra > end_frame) {
1794 break;
1795 }
1796 FrameLink *link = static_cast<FrameLink *>(MEM_callocN(sizeof(FrameLink), "Marker Key Link"));
1797 link->frame = column->cfra;
1798 BLI_addtail(target_frames, link);
1799 }
1800 ED_keylist_free(keylist);
1801}
1802
1803static void get_selected_frames(ListBase *pflinks, ListBase /*FrameLink*/ *target_frames)
1804{
1805 AnimKeylist *keylist = ED_keylist_create();
1806 LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) {
1807 LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) {
1808 FCurve *fcu = (FCurve *)ld->data;
1809 fcurve_to_keylist(nullptr, fcu, keylist, 0, {-FLT_MAX, FLT_MAX});
1810 }
1811 }
1812 LISTBASE_FOREACH (ActKeyColumn *, column, ED_keylist_listbase(keylist)) {
1813 if (!column->sel) {
1814 continue;
1815 }
1816 FrameLink *link = static_cast<FrameLink *>(MEM_callocN(sizeof(FrameLink), "Marker Key Link"));
1817 link->frame = column->cfra;
1818 BLI_addtail(target_frames, link);
1819 }
1820 ED_keylist_free(keylist);
1821}
1822
1823/* --------------------------------- */
1824
1826{
1827 Scene *scene = CTX_data_scene(C);
1828 ViewLayer *view_layer = CTX_data_view_layer(C);
1829 View3D *v3d = CTX_wm_view3d(C);
1830
1831 ListBase pflinks = {nullptr, nullptr};
1832
1833 const int mode = RNA_enum_get(op->ptr, "mode");
1834
1835 /* Isolate F-Curves related to the selected bones. */
1836 poseAnim_mapping_get(C, &pflinks);
1837
1838 if (BLI_listbase_is_empty(&pflinks)) {
1839 /* There is a change the reason the list is empty is
1840 * that there is no valid object to propagate poses for.
1841 * This is very unlikely though, so we focus on the most likely issue. */
1842 BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
1843 return OPERATOR_CANCELLED;
1844 }
1845
1846 const float end_frame = RNA_float_get(op->ptr, "end_frame");
1847 const float current_frame = BKE_scene_frame_get(scene);
1848
1849 ListBase target_frames = {nullptr, nullptr};
1850
1851 switch (mode) {
1853 float target_frame = find_next_key(&pflinks, current_frame);
1854 FrameLink *link = static_cast<FrameLink *>(MEM_callocN(sizeof(FrameLink), "Next Key Link"));
1855 link->frame = target_frame;
1856 BLI_addtail(&target_frames, link);
1857 propagate_curve_values(&pflinks, current_frame, &target_frames);
1858 break;
1859 }
1860
1862 float target_frame = find_last_key(&pflinks);
1863 FrameLink *link = static_cast<FrameLink *>(MEM_callocN(sizeof(FrameLink), "Last Key Link"));
1864 link->frame = target_frame;
1865 BLI_addtail(&target_frames, link);
1866 propagate_curve_values(&pflinks, current_frame, &target_frames);
1867 break;
1868 }
1869
1871 get_selected_marker_positions(scene, &target_frames);
1872 propagate_curve_values(&pflinks, current_frame, &target_frames);
1873 break;
1874 }
1875
1877 get_keyed_frames_in_range(&pflinks, current_frame, FLT_MAX, &target_frames);
1878 propagate_curve_values(&pflinks, current_frame, &target_frames);
1879 break;
1880 }
1882 get_keyed_frames_in_range(&pflinks, current_frame, end_frame, &target_frames);
1883 propagate_curve_values(&pflinks, current_frame, &target_frames);
1884 break;
1885 }
1887 get_selected_frames(&pflinks, &target_frames);
1888 propagate_curve_values(&pflinks, current_frame, &target_frames);
1889 break;
1890 }
1891 }
1892
1893 BLI_freelistN(&target_frames);
1894
1895 /* Free temp data. */
1896 poseAnim_mapping_free(&pflinks);
1897
1898 /* Updates + notifiers. */
1899 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
1900 poseAnim_mapping_refresh(C, scene, ob);
1901 }
1903
1904 return OPERATOR_FINISHED;
1905}
1906
1907/* --------------------------------- */
1908
1910{
1911 static const EnumPropertyItem terminate_items[] = {
1913 "NEXT_KEY",
1914 0,
1915 "To Next Keyframe",
1916 "Propagate pose to first keyframe following the current frame only"},
1918 "LAST_KEY",
1919 0,
1920 "To Last Keyframe",
1921 "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
1923 "BEFORE_FRAME",
1924 0,
1925 "Before Frame",
1926 "Propagate pose to all keyframes between current frame and 'Frame' property"},
1928 "BEFORE_END",
1929 0,
1930 "Before Last Keyframe",
1931 "Propagate pose to all keyframes from current frame until no more are found"},
1933 "SELECTED_KEYS",
1934 0,
1935 "On Selected Keyframes",
1936 "Propagate pose to all selected keyframes"},
1938 "SELECTED_MARKERS",
1939 0,
1940 "On Selected Markers",
1941 "Propagate pose to all keyframes occurring on frames with Scene Markers after the current "
1942 "frame"},
1943 {0, nullptr, 0, nullptr, nullptr},
1944 };
1945
1946 /* identifiers */
1947 ot->name = "Propagate Pose";
1948 ot->idname = "POSE_OT_propagate";
1949 ot->description =
1950 "Copy selected aspects of the current pose to subsequent poses already keyframed";
1951
1952 /* callbacks */
1954 ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
1955
1956 /* flag */
1958
1959 /* properties */
1960 /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
1962 "mode",
1963 terminate_items,
1965 "Terminate Mode",
1966 "Method used to determine when to stop propagating pose to keyframes");
1968 "end_frame",
1969 250.0,
1970 FLT_MIN,
1971 FLT_MAX,
1972 "End Frame",
1973 "Frame to stop propagating frames to (for 'Before Frame' mode)",
1974 1.0,
1975 250.0);
1976}
1977
1978/* **************************************************** */
Functions to modify FCurves.
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
#define FOREACH_OBJECT_IN_MODE_END
Definition BKE_layer.hh:382
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, eObjectMode mode)
#define FOREACH_OBJECT_IN_MODE_BEGIN(_scene, _view_layer, _v3d, _object_type, _object_mode, _instance)
Definition BKE_layer.hh:377
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2331
@ B_UNIT_NONE
Definition BKE_unit.hh:106
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE float interpf(float target, float origin, float t)
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
float normalize_qt(float q[4])
float normalize_qt_qt(float r[4], const float q[4])
void copy_qt_qt(float q[4], const float a[4])
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4])
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
#define IFACE_(msgid)
@ ROT_MODE_AXISANGLE
@ POSE_BBONE_SHAPE
@ POSE_ROT
@ POSE_LOC
@ POSE_SIZE
@ POSE_LOCKED
@ INSERTKEY_NOFLAGS
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define MINAFRAME
#define MAXFRAME
@ V3D_OVERLAY_HIDE_BONES
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void initNumInput(NumInput *n)
Definition numinput.cc:70
#define NUM_STR_REP_LEN
void outputNumInput(NumInput *n, char *str, const UnitSettings *unit_settings)
Definition numinput.cc:88
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:312
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
bool ED_operator_posemode(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void ED_slider_status_string_get(const tSlider *slider, char *status_string, size_t size_of_status_string)
Definition ed_draw.cc:505
void ED_slider_init(tSlider *slider, const wmEvent *event)
Definition ed_draw.cc:467
void ED_slider_destroy(bContext *C, tSlider *slider)
Definition ed_draw.cc:553
tSlider * ED_slider_create(bContext *C)
Definition ed_draw.cc:427
bool ED_slider_modal(tSlider *slider, const wmEvent *event)
Definition ed_draw.cc:472
void ED_slider_factor_bounds_set(tSlider *slider, float factor_bound_lower, float factor_bound_upper)
Definition ed_draw.cc:596
float ED_slider_factor_get(const tSlider *slider)
Definition ed_draw.cc:566
void ED_slider_factor_set(tSlider *slider, float factor)
Definition ed_draw.cc:571
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_INT
Definition RNA_types.hh:66
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define UI_MAX_DRAW_STR
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
@ OPTYPE_GRAB_CURSOR_X
Definition WM_types.hh:170
@ KM_PRESS
Definition WM_types.hh:284
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, const bool only_selected)
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
void poseAnim_mapping_free(ListBase *pfLinks)
void poseAnim_mapping_reset(ListBase *pfLinks)
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
Object * poseAnim_object_get(Object *ob_)
void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
LinkData * poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
volatile int lock
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
int len
draw_view in_light_buf[] float
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
const ListBase * ED_keylist_listbase(const AnimKeylist *keylist)
bool ED_keylist_is_empty(const AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float2 fabs(const float2 a)
ePoseSlide_Modes
Definition pose_slide.cc:92
@ POSESLIDE_BLEND
@ POSESLIDE_BREAKDOWN
Definition pose_slide.cc:98
@ POSESLIDE_PUSH
Definition pose_slide.cc:94
@ POSESLIDE_BLEND_REST
Definition pose_slide.cc:99
@ POSESLIDE_RELAX
Definition pose_slide.cc:96
static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *event)
static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
void POSE_OT_breakdown(wmOperatorType *ot)
static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static const EnumPropertyItem prop_channels_types[]
static void pose_slide_apply_val(tPoseSlideOp *pso, const FCurve *fcu, Object *ob, float *val)
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void pose_slide_reset(tPoseSlideOp *pso)
static void pose_slide_cancel(bContext *C, wmOperator *op)
static int pose_slide_blend_to_neighbors_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void get_keyed_frames_in_range(ListBase *pflinks, const float start_frame, const float end_frame, ListBase *target_frames)
ePoseSlide_AxisLock
Definition pose_slide.cc:85
@ PS_LOCK_Z
Definition pose_slide.cc:88
@ PS_LOCK_Y
Definition pose_slide.cc:87
@ PS_LOCK_X
Definition pose_slide.cc:86
static const EnumPropertyItem prop_axis_lock_types[]
static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat)
static void pose_slide_opdef_properties(wmOperatorType *ot)
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
static float find_next_key(ListBase *pflinks, const float start_frame)
static int pose_slide_blend_rest_exec(bContext *C, wmOperator *op)
static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
static int pose_slide_blend_to_neighbors_exec(bContext *C, wmOperator *op)
void POSE_OT_blend_with_rest(wmOperatorType *ot)
void POSE_OT_propagate(wmOperatorType *ot)
static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso)
static int pose_slide_blend_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
static float find_last_key(ListBase *pflinks)
static void propagate_curve_values(ListBase *pflinks, const float source_frame, ListBase *target_frames)
static int pose_slide_push_exec(bContext *C, wmOperator *op)
static int pose_propagate_exec(bContext *C, wmOperator *op)
static bool pose_frame_range_from_object_get(tPoseSlideOp *pso, Object *ob, float *prev_frame, float *next_frame)
void POSE_OT_relax(wmOperatorType *ot)
static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], const char propName[])
ePoseSlide_Channels
@ PS_TFM_SIZE
@ PS_TFM_LOC
@ PS_TFM_PROPS
@ PS_TFM_ALL
@ PS_TFM_BBONE_SHAPE
@ PS_TFM_ROT
static int pose_slide_relax_exec(bContext *C, wmOperator *op)
void POSE_OT_push(wmOperatorType *ot)
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value)
static void get_selected_frames(ListBase *pflinks, ListBase *target_frames)
static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
ePosePropagate_Termination
@ POSE_PROPAGATE_LAST_KEY
@ POSE_PROPAGATE_BEFORE_FRAME
@ POSE_PROPAGATE_SELECTED_MARKERS
@ POSE_PROPAGATE_BEFORE_END
@ POSE_PROPAGATE_NEXT_KEY
@ POSE_PROPAGATE_SELECTED_KEYS
static void get_selected_marker_positions(Scene *scene, ListBase *target_frames)
static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
static void pose_slide_exit(bContext *C, wmOperator *op)
void POSE_OT_blend_to_neighbors(wmOperatorType *ot)
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
bool RNA_property_array_check(PropertyRNA *prop)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
#define FLT_MAX
Definition stdcycles.h:14
ActKeyColumn * prev
ActKeyColumn * next
float vec[3][3]
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
void * data
void * first
short idx_max
int unit_type[NUM_MAX_ELEMENTS]
struct bPose * pose
struct AnimData * adt
struct RenderData r
ListBase spacedata
View3DOverlay overlay
ePoseSlide_Channels channels
NumInput num
ePoseSlide_AxisLock axislock
ARegion * region
tSlider * slider
ScrArea * area
AnimKeylist * keylist
ePoseSlide_Modes mode
ListBase pfLinks
Scene * scene
blender::Array< tPoseSlideObject > ob_data_array
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EW_SCROLL
Definition wm_cursors.hh:53
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ RIGHTMOUSE
@ EVT_YKEY
@ EVT_SKEY
@ EVT_XKEY
@ EVT_CKEY
@ EVT_GKEY
@ EVT_PADENTER
@ MOUSEMOVE
@ EVT_HKEY
@ LEFTMOUSE
@ EVT_ZKEY
@ EVT_ESCKEY
@ EVT_RKEY
@ EVT_BKEY
@ EVT_RETKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125