Blender V5.0
pose_transform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DNA_anim_types.h"
10#include "DNA_armature_types.h"
12#include "DNA_object_types.h"
13#include "DNA_scene_types.h"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_path_utils.hh"
22#include "BLI_string.h"
23#include "BLI_string_utf8.h"
24#include "BLI_string_utils.hh"
25
26#include "BKE_action.hh"
27#include "BKE_animsys.h"
28#include "BKE_appdir.hh"
29#include "BKE_armature.hh"
31#include "BKE_blendfile.hh"
32#include "BKE_context.hh"
33#include "BKE_idprop.hh"
34#include "BKE_layer.hh"
35#include "BKE_lib_query.hh"
36#include "BKE_main.hh"
37#include "BKE_object.hh"
38#include "BKE_report.hh"
39
40#include "DEG_depsgraph.hh"
42
43#include "RNA_access.hh"
44#include "RNA_define.hh"
45#include "RNA_prototypes.hh"
46
47#include "WM_api.hh"
48#include "WM_types.hh"
49
50#include "ED_armature.hh"
51#include "ED_keyframing.hh"
52#include "ED_screen.hh"
53
54#include "ANIM_armature.hh"
56#include "ANIM_keyframing.hh"
57#include "ANIM_keyingsets.hh"
58
60#include "UI_resources.hh"
61
62#include "armature_intern.hh"
63
64/* -------------------------------------------------------------------- */
67
68static void pose_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
69{
70 BLI_path_join(filepath, filepath_maxncpy, BKE_tempdir_base(), "copybuffer_pose.blend");
71}
72
74
75/* -------------------------------------------------------------------- */
78
79/* helper for apply_armature_pose2bones - fixes parenting of objects
80 * that are bone-parented to armature */
81static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
82{
83 /* Depsgraph has been ensured to be evaluated at the beginning of the operator.
84 *
85 * Must not evaluate depsgraph here yet, since this will ruin object matrix which we want to
86 * preserve after other changes has been done in the operator.
87 *
88 * TODO(sergey): This seems very similar to `ignore_parent_tx()`, which was now ensured to work
89 * quite reliably. Can we de-duplicate the code? Or at least verify we don't need an extra logic
90 * in this function. */
92 Main *bmain = CTX_data_main(C);
93
94 /* go through all objects in database */
95 for (Object *ob = static_cast<Object *>(bmain->objects.first); ob;
96 ob = static_cast<Object *>(ob->id.next))
97 {
98 /* if parent is bone in this armature, apply corrections */
99 if ((ob->parent == armob) && (ob->partype == PARBONE)) {
100 /* apply current transform from parent (not yet destroyed),
101 * then calculate new parent inverse matrix
102 */
103 BKE_object_apply_mat4(ob, ob->object_to_world().ptr(), false, false);
104
105 invert_m4_m4(ob->parentinv, BKE_object_calc_parent(depsgraph, scene, ob).ptr());
106 }
107 }
108}
109
110/* Sets the bone head, tail and roll to match the supplied parameters. */
112 const float pose_mat[4][4],
113 const float new_tail[3],
114 float r_new_arm_mat[4][4])
115{
116 /* Simply copy the head/tail values from pchan over to curbone. */
117 copy_v3_v3(curbone->head, pose_mat[3]);
118 copy_v3_v3(curbone->tail, new_tail);
119
120 /* Fix roll:
121 * 1. find auto-calculated roll value for this bone now
122 * 2. remove this from the 'visual' y-rotation
123 */
124 {
125 float premat[3][3], pmat[3][3];
126 float delta[3];
127
128 /* Obtain new auto y-rotation. */
129 sub_v3_v3v3(delta, curbone->tail, curbone->head);
130
131 copy_m3_m4(pmat, pose_mat);
132 mat3_vec_to_roll(pmat, delta, &curbone->roll);
133
134 /* Compute new rest pose matrix if requested. */
135 if (r_new_arm_mat) {
136 vec_roll_to_mat3(delta, curbone->roll, premat);
137 copy_m4_m3(r_new_arm_mat, premat);
138 copy_v3_v3(r_new_arm_mat[3], pose_mat[3]);
139 }
140 }
141}
142
143/* Copy properties over from pchan to curbone and reset channels. */
145 bPoseChannel *pchan,
146 const bPoseChannel *pchan_eval)
147{
148 /* Combine pose and rest values for bendy bone settings,
149 * then clear the pchan values (so we don't get a double-up).
150 */
151 if (pchan->bone->segments > 1) {
152 /* Combine rest/pose values. */
153 curbone->curve_in_x += pchan_eval->curve_in_x;
154 curbone->curve_in_z += pchan_eval->curve_in_z;
155 curbone->curve_out_x += pchan_eval->curve_out_x;
156 curbone->curve_out_z += pchan_eval->curve_out_z;
157 curbone->roll1 += pchan_eval->roll1;
158 curbone->roll2 += pchan_eval->roll2;
159 curbone->ease1 += pchan_eval->ease1;
160 curbone->ease2 += pchan_eval->ease2;
161
162 mul_v3_v3(curbone->scale_in, pchan_eval->scale_in);
163 mul_v3_v3(curbone->scale_out, pchan_eval->scale_out);
164
165 /* Reset pose values. */
166 pchan->curve_in_x = pchan->curve_out_x = 0.0f;
167 pchan->curve_in_z = pchan->curve_out_z = 0.0f;
168 pchan->roll1 = pchan->roll2 = 0.0f;
169 pchan->ease1 = pchan->ease2 = 0.0f;
170
171 copy_v3_fl(pchan->scale_in, 1.0f);
172 copy_v3_fl(pchan->scale_out, 1.0f);
173 }
174
175 /* Clear transform values for pchan. */
176 zero_v3(pchan->loc);
177 zero_v3(pchan->eul);
178 unit_qt(pchan->quat);
179 unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
180 pchan->scale[0] = pchan->scale[1] = pchan->scale[2] = 1.0f;
181}
182
183/* Adjust the current edit position of the bone using the pose space matrix. */
185 bPoseChannel *pchan,
186 const float delta_mat[4][4],
187 float r_new_arm_mat[4][4])
188{
189 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
190 float delta[3], new_tail[3], premat[3][3], new_pose[4][4];
191
192 /* Current orientation matrix. */
193 sub_v3_v3v3(delta, curbone->tail, curbone->head);
194 vec_roll_to_mat3(delta, curbone->roll, premat);
195
196 /* New location and orientation. */
197 mul_m4_m4m3(new_pose, delta_mat, premat);
198 mul_v3_m4v3(new_pose[3], delta_mat, curbone->head);
199 mul_v3_m4v3(new_tail, delta_mat, curbone->tail);
200
201 applyarmature_set_edit_position(curbone, new_pose, new_tail, r_new_arm_mat);
202}
203
204/* Data about parent position for Apply To Selected mode. */
207
208 /* New rest position of the bone with scale included. */
209 float new_rest_mat[4][4];
210 /* New arm_mat of the bone == new_rest_mat without scale. */
211 float new_arm_mat[4][4];
212};
213
214/* Recursive walk for Apply To Selected mode; pstate nullptr unless child of an applied bone. */
216 bPose *pose,
217 bPose *pose_eval,
218 Bone *bone,
221{
222 bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
223 const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
224
225 if (!pchan || !pchan_eval) {
226 return;
227 }
228
229 ApplyArmature_ParentState new_pstate{};
230 new_pstate.bone = bone;
231
232 if (std::find_if(selected.begin(), selected.end(), [&](const PointerRNA &ptr) {
233 return ptr.data == pchan;
234 }) != selected.end())
235 {
236 /* SELECTED BONE: Snap to final pose transform minus un-applied parent effects.
237 *
238 * I.e. bone position with accumulated parent effects but no local
239 * transformation will match the original final pose_mat.
240 *
241 * Pose channels are reset as expected.
242 */
243 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
244 BoneParentTransform invparent;
245 float new_tail[3];
246
247 if (pchan->parent) {
248 BoneParentTransform old_bpt, new_bpt;
249 float offs_bone[4][4];
250
251 /* Parent effects on the bone transform that have to be removed. */
252 BKE_bone_offset_matrix_get(bone, offs_bone);
254 bone->inherit_scale_mode,
255 offs_bone,
256 bone->parent->arm_mat,
257 pchan_eval->parent->pose_mat,
258 &old_bpt);
259
260 /* Applied parent effects that have to be kept, if any. */
261 float (*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat;
263 bone->inherit_scale_mode,
264 offs_bone,
265 bone->parent->arm_mat,
266 new_parent_pose,
267 &new_bpt);
268
270 BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
271 }
272 else {
274 }
275
276 /* Apply change without inherited unapplied parent transformations. */
277 BKE_bone_parent_transform_apply(&invparent, pchan_eval->pose_mat, new_pstate.new_rest_mat);
278
279 copy_v3_fl3(new_tail, 0.0, bone->length, 0.0);
280 mul_m4_v3(new_pstate.new_rest_mat, new_tail);
281
283 curbone, new_pstate.new_rest_mat, new_tail, new_pstate.new_arm_mat);
284 applyarmature_transfer_properties(curbone, pchan, pchan_eval);
285
286 pstate = &new_pstate;
287 }
288 else if (pstate) {
289 /* UNSELECTED CHILD OF SELECTED: Include applied parent effects.
290 *
291 * The inherited transform of applied (selected) bones is baked
292 * into the rest pose so that the final bone position doesn't
293 * change.
294 *
295 * Pose channels are not changed, with the exception of the inherited
296 * applied parent scale being baked into the location pose channel.
297 */
299 float offs_bone[4][4], delta[4][4], old_chan_loc[3];
300
301 /* Include applied parent effects. */
302 BKE_bone_offset_matrix_get(bone, offs_bone);
304 bone->inherit_scale_mode,
305 offs_bone,
306 pstate->bone->arm_mat,
307 pstate->new_rest_mat,
308 &bpt);
309
310 unit_m4(new_pstate.new_rest_mat);
311 BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
312
313 /* Bone location channel in pose space relative to bone head. */
314 mul_v3_mat3_m4v3(old_chan_loc, bpt.loc_mat, pchan_eval->loc);
315
316 /* Apply the change to the rest bone position. */
317 invert_m4_m4(delta, bone->arm_mat);
318 mul_m4_m4m4(delta, new_pstate.new_rest_mat, delta);
319
320 applyarmature_adjust_edit_position(arm, pchan, delta, new_pstate.new_arm_mat);
321
322 /* Location pose channel has to be updated, because it is affected
323 * by parent scaling, and the rest pose has no scale by definition. */
324 if (!(bone->flag & BONE_CONNECTED) && !is_zero_v3(old_chan_loc)) {
325 float inv_parent_arm[4][4];
326
327 /* Compute the channel coordinate space matrices for the new rest state. */
328 invert_m4_m4(inv_parent_arm, pstate->new_arm_mat);
329 mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat);
331 bone->inherit_scale_mode,
332 offs_bone,
333 pstate->new_arm_mat,
334 pstate->new_arm_mat,
335 &bpt);
336
337 /* Re-apply the location to keep the final effect. */
338 invert_m4(bpt.loc_mat);
339 mul_v3_mat3_m4v3(pchan->loc, bpt.loc_mat, old_chan_loc);
340 }
341
342 pstate = &new_pstate;
343 }
344
345 LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
346 applyarmature_process_selected_recursive(arm, pose, pose_eval, child, selected, pstate);
347 }
348}
349
350/* Reset bone constraint so that it is correct after the pose has been applied. */
352{
353 /* TODO(Sybren): This function needs too much knowledge of the internals of specific constraints.
354 * When it is extended with one or two more constraints, move the functionality into a
355 * bConstraintTypeInfo callback function. */
356 switch (constraint->type) {
358 bStretchToConstraint *stretch_to = static_cast<bStretchToConstraint *>(constraint->data);
359 stretch_to->orglength = 0.0f; /* Force recalculation on next evaluation. */
360 break;
361 }
362 default:
363 /* Most constraints don't need resetting. */
364 break;
365 }
366}
367
368/* Reset bone constraints of the given pose channel so that they are correct after the pose has
369 * been applied. */
371{
372 LISTBASE_FOREACH (bConstraint *, constraint, &pchan->constraints) {
374 }
375}
376
377/* Reset all (or only selected) bone constraints so that they are correct after the pose has been
378 * applied. */
379static void applyarmature_reset_constraints(bPose *pose, const bool use_selected)
380{
381 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
382 BLI_assert(pchan->bone != nullptr);
383 if (use_selected && (pchan->flag & POSE_SELECTED) == 0) {
384 continue;
385 }
387 }
388}
389
390/* Set the current pose as the rest-pose. */
392{
393 Main *bmain = CTX_data_main(C);
395 Scene *scene = CTX_data_scene(C);
396 /* must be active object, not edit-object */
398 const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
400 bPose *pose;
401 blender::Vector<PointerRNA> selected_bones;
402
403 const bool use_selected = RNA_boolean_get(op->ptr, "selected");
404
405 /* don't check if editmode (should be done by caller) */
406 if (ob->type != OB_ARMATURE) {
407 return OPERATOR_CANCELLED;
408 }
410 BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature");
411 return OPERATOR_CANCELLED;
412 }
413
414 /* helpful warnings... */
415 /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
416 if (ob->adt && ob->adt->action) {
419 "Actions on this armature will be destroyed by this new rest pose as the "
420 "transforms stored are relative to the old rest pose");
421 }
422
423 /* Find selected bones before switching to edit mode. */
424 if (use_selected) {
425 CTX_data_selected_pose_bones(C, &selected_bones);
426
427 if (selected_bones.is_empty()) {
428 return OPERATOR_CANCELLED;
429 }
430 }
431
432 /* Get edit-bones of active armature to alter. */
434
435 /* Get pose of active object and move it out of pose-mode. */
436 pose = ob->pose;
437
438 if (use_selected) {
439 /* The selected only mode requires a recursive walk to handle parent-child relations. */
440 LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
442 arm, pose, ob_eval->pose, bone, selected_bones, nullptr);
443 }
444 }
445 else {
446 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
447 const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
448 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
449
451 curbone, pchan_eval->pose_mat, pchan_eval->pose_tail, nullptr);
452 applyarmature_transfer_properties(curbone, pchan, pchan_eval);
453 }
454 }
455
456 /* Convert edit-bones back to bones, and then free the edit-data. */
457 ED_armature_from_edit(bmain, arm);
459
460 /* Flush positions of pose-bones. */
461 BKE_pose_where_is(depsgraph, scene, ob);
462
463 /* fix parenting of objects which are bone-parented */
465
466 /* For the affected bones, reset specific constraints that are now known to be invalid. */
467 applyarmature_reset_constraints(pose, use_selected);
468
469 /* NOTE: notifier might evolve. */
472
473 return OPERATOR_FINISHED;
474}
475
477{
478 uiLayout *layout = op->layout;
480
482
483 layout->prop(&ptr, "selected", UI_ITEM_NONE, std::nullopt, ICON_NONE);
484}
485
487{
488 /* identifiers */
489 ot->name = "Apply Pose as Rest Pose";
490 ot->idname = "POSE_OT_armature_apply";
491 ot->description = "Apply the current pose as the new rest pose";
492
493 /* callbacks */
495 ot->poll = ED_operator_posemode;
497
498 /* flags */
500
501 RNA_def_boolean(ot->srna,
502 "selected",
503 false,
504 "Selected Only",
505 "Only apply the selected bones (with propagation to children)");
506}
507
509
510/* -------------------------------------------------------------------- */
515
517{
518 const Scene *scene = CTX_data_scene(C);
519 ViewLayer *view_layer = CTX_data_view_layer(C);
520 View3D *v3d = CTX_wm_view3d(C);
521
522 /* Needed to ensure #bPoseChannel.pose_mat are up to date. */
524
525 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
526 const bArmature *arm = static_cast<const bArmature *>(ob->data);
527
528 int chanbase_len = BLI_listbase_count(&ob->pose->chanbase);
529 /* Storage for the calculated matrices to prevent reading from modified values.
530 * NOTE: this could be avoided if children were always calculated before parents
531 * however ensuring this is involved and doesn't give any significant advantage. */
532 struct XFormArray {
533 float matrix[4][4];
534 bool is_set;
535 } *pchan_xform_array = MEM_malloc_arrayN<XFormArray>(chanbase_len, __func__);
536 bool changed = false;
537
538 int i;
539 LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) {
540 if (!blender::animrig::bone_is_selected(arm, pchan)) {
541 pchan_xform_array[i].is_set = false;
542 continue;
543 }
544
545 /* `chan_mat` already contains the delta transform from rest pose to pose-mode pose
546 * as that is baked into there so that B-Bones will work. Once we've set this as the
547 * new raw-transform components, don't recalculate the poses yet, otherwise IK result will
548 * change, thus changing the result we may be trying to record. */
549
550 /* NOTE: For some reason `pchan->chan_mat` can't be used here as it gives odd
551 * rotation/offset, see #38251.
552 * Using `pchan->pose_mat` and bringing it back in bone space seems to work as expected!
553 * This matches how visual key-framing works. */
554 BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, pchan_xform_array[i].matrix);
555 pchan_xform_array[i].is_set = true;
556 changed = true;
557 }
558
559 if (changed) {
560 /* Perform separately to prevent feedback loop. */
561 LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) {
562 if (!pchan_xform_array[i].is_set) {
563 continue;
564 }
565 BKE_pchan_apply_mat4(pchan, pchan_xform_array[i].matrix, true);
566 }
567
569
570 /* NOTE: notifier might evolve. */
572 }
573
574 MEM_freeN(pchan_xform_array);
575 }
577
578 return OPERATOR_FINISHED;
579}
580
582{
583 /* identifiers */
584 ot->name = "Apply Visual Transform to Pose";
585 ot->idname = "POSE_OT_visual_transform_apply";
586 ot->description = "Apply final constrained position of pose bones to their transform";
587
588 /* callbacks */
590 ot->poll = ED_operator_posemode;
591
592 /* flags */
594}
595
597
598/* -------------------------------------------------------------------- */
601
612 bPoseChannel *chan,
613 const bool selOnly,
614 const bool flip)
615{
616 char name[MAXBONENAME];
617
618 /* get the name - if flipping, we must flip this first */
619 if (flip) {
620 BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
621 }
622 else {
623 STRNCPY_UTF8(name, chan->name);
624 }
625
626 /* only copy when:
627 * 1) channel exists - poses are not meant to add random channels to anymore
628 * 2) if selection-masking is on, channel is selected -
629 * only selected bones get pasted on, allowing making both sides symmetrical.
630 */
632 if (pchan == nullptr) {
633 return nullptr;
634 }
635 if (selOnly && (pchan->flag & POSE_SELECTED) == 0) {
636 return nullptr;
637 }
638
639 /* only loc rot size
640 * - only copies transform info for the pose
641 */
642 copy_v3_v3(pchan->loc, chan->loc);
643 copy_v3_v3(pchan->scale, chan->scale);
644
645 /* check if rotation modes are compatible (i.e. do they need any conversions) */
646 if (pchan->rotmode == chan->rotmode) {
647 /* copy the type of rotation in use */
648 if (pchan->rotmode > 0) {
649 copy_v3_v3(pchan->eul, chan->eul);
650 }
651 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
652 copy_v3_v3(pchan->rotAxis, chan->rotAxis);
653 pchan->rotAngle = chan->rotAngle;
654 }
655 else {
656 copy_qt_qt(pchan->quat, chan->quat);
657 }
658 }
659 else if (pchan->rotmode > 0) {
660 /* quat/axis-angle to euler */
661 if (chan->rotmode == ROT_MODE_AXISANGLE) {
662 axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
663 }
664 else {
665 quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
666 }
667 }
668 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
669 /* quat/euler to axis angle */
670 if (chan->rotmode > 0) {
671 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
672 }
673 else {
674 quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
675 }
676 }
677 else {
678 /* euler/axis-angle to quat */
679 if (chan->rotmode > 0) {
680 eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
681 }
682 else {
683 axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
684 }
685 }
686
687 /* B-Bone posing options should also be included... */
688 pchan->curve_in_x = chan->curve_in_x;
689 pchan->curve_in_z = chan->curve_in_z;
690 pchan->curve_out_x = chan->curve_out_x;
691 pchan->curve_out_z = chan->curve_out_z;
692
693 pchan->roll1 = chan->roll1;
694 pchan->roll2 = chan->roll2;
695 pchan->ease1 = chan->ease1;
696 pchan->ease2 = chan->ease2;
697
698 copy_v3_v3(pchan->scale_in, chan->scale_in);
699 copy_v3_v3(pchan->scale_out, chan->scale_out);
700
701 /* paste flipped pose? */
702 if (flip) {
703 pchan->loc[0] *= -1;
704
705 pchan->curve_in_x *= -1;
706 pchan->curve_out_x *= -1;
707 pchan->roll1 *= -1; /* XXX? */
708 pchan->roll2 *= -1; /* XXX? */
709
710 /* has to be done as eulers... */
711 if (pchan->rotmode > 0) {
712 pchan->eul[1] *= -1;
713 pchan->eul[2] *= -1;
714 }
715 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
716 float eul[3];
717
719 eul[1] *= -1;
720 eul[2] *= -1;
722 }
723 else {
724 float eul[3];
725
726 normalize_qt(pchan->quat);
727 quat_to_eul(eul, pchan->quat);
728 eul[1] *= -1;
729 eul[2] *= -1;
730 eul_to_quat(pchan->quat, eul);
731 }
732 }
733
734 /* ID properties */
735 if (chan->prop) {
736 if (pchan->prop) {
737 /* if we have existing properties on a bone, just copy over the values of
738 * matching properties (i.e. ones which will have some impact) on to the
739 * target instead of just blinding replacing all [
740 */
741 IDP_SyncGroupValues(pchan->prop, chan->prop);
742 }
743 else {
744 /* no existing properties, so assume that we want copies too? */
745 pchan->prop = IDP_CopyProperty(chan->prop);
746 }
747 }
748 if (chan->system_properties) {
749 /* Same logic as above for system IDProperties, for now. */
750 if (pchan->system_properties) {
752 }
753 else {
755 }
756 }
757
758 return pchan;
759}
760
762
763/* -------------------------------------------------------------------- */
766
768{
769 using namespace blender::bke::blendfile;
770
771 Main *bmain = CTX_data_main(C);
773
774 /* Sanity checking. */
775 if (ELEM(nullptr, ob, ob->pose)) {
776 BKE_report(op->reports, RPT_ERROR, "No pose to copy");
777 return OPERATOR_CANCELLED;
778 }
779 if (ID_IS_PACKED(&ob->id)) {
780 /* Direct link/append of packed IDs is not supported currently, so neither is their
781 * copy/pasting. */
782 BKE_report(op->reports, RPT_ERROR, "Cannot copy/paste packed data");
783 return OPERATOR_CANCELLED;
784 }
785
786 bArmature *armature = static_cast<bArmature *>(ob->data);
787 BLI_assert_msg(armature, "If an armature object has a pose, it should have armature data");
788 /* Taking off the selection flag in case bones are hidden so they are not
789 * applied when pasting. */
790 LISTBASE_FOREACH (bPoseChannel *, pose_bone, &ob->pose->chanbase) {
791 if (!blender::animrig::bone_is_visible(armature, pose_bone)) {
792 pose_bone->flag &= ~POSE_SELECTED;
793 }
794 }
795
796 PartialWriteContext copybuffer{*bmain};
797 copybuffer.id_add(
798 &ob->id,
800 (PartialWriteContext::IDAddOperations::MAKE_LOCAL |
801 PartialWriteContext::IDAddOperations::SET_FAKE_USER |
802 PartialWriteContext::IDAddOperations::SET_CLIPBOARD_MARK)},
803 [ob](LibraryIDLinkCallbackData *cb_data,
805 /* Only include `ob->data` (i.e. the Armature) dependency. */
806 if (*(cb_data->id_pointer) == ob->data) {
807 return (PartialWriteContext::IDAddOperations::MAKE_LOCAL |
808 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES);
809 }
811 });
812
813 char filepath[FILE_MAX];
814 pose_copybuffer_filepath_get(filepath, sizeof(filepath));
815 copybuffer.write(filepath, *op->reports);
816
817 /* We are all done! */
818 BKE_report(op->reports, RPT_INFO, "Copied pose to internal clipboard");
819 return OPERATOR_FINISHED;
820}
821
823{
824 /* identifiers */
825 ot->name = "Copy Pose";
826 ot->idname = "POSE_OT_copy";
827 ot->description = "Copy the current pose of the selected bones to the internal clipboard";
828
829 /* API callbacks. */
830 ot->exec = pose_copy_exec;
831 ot->poll = ED_operator_posemode;
832
833 /* flag */
834 ot->flag = OPTYPE_REGISTER;
835}
836
838
839/* -------------------------------------------------------------------- */
842
844{
846 Scene *scene = CTX_data_scene(C);
847 const bool flip = RNA_boolean_get(op->ptr, "flipped");
848 bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
849
850 /* Get KeyingSet to use. */
853
854 /* Sanity checks. */
855 if (ELEM(nullptr, ob, ob->pose)) {
856 return OPERATOR_CANCELLED;
857 }
858
859 /* Read copy buffer .blend file. */
860 char filepath[FILE_MAX];
861 Main *temp_bmain = BKE_main_new();
863
864 pose_copybuffer_filepath_get(filepath, sizeof(filepath));
865 if (!BKE_copybuffer_read(temp_bmain, filepath, op->reports, FILTER_ID_OB)) {
866 BKE_report(op->reports, RPT_ERROR, "Internal clipboard is empty");
867 BKE_main_free(temp_bmain);
868 return OPERATOR_CANCELLED;
869 }
870 /* Make sure data from this file is usable for pose paste. */
871 if (!BLI_listbase_is_single(&temp_bmain->objects)) {
872 BKE_report(op->reports, RPT_ERROR, "Internal clipboard is not from pose mode");
873 BKE_main_free(temp_bmain);
874 return OPERATOR_CANCELLED;
875 }
876
877 Object *object_from = static_cast<Object *>(temp_bmain->objects.first);
878 bPose *pose_from = object_from->pose;
879 if (pose_from == nullptr) {
880 BKE_report(op->reports, RPT_ERROR, "Internal clipboard has no pose");
881 BKE_main_free(temp_bmain);
882 return OPERATOR_CANCELLED;
883 }
884
885 /* If selOnly option is enabled, if user hasn't selected any bones,
886 * just go back to default behavior to be more in line with other
887 * pose tools.
888 */
889 if (selOnly) {
890 if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
891 selOnly = false;
892 }
893 }
894
895 /* Safely merge all of the channels in the buffer pose into any
896 * existing pose.
897 */
898 LISTBASE_FOREACH (bPoseChannel *, chan, &pose_from->chanbase) {
899 if (chan->flag & POSE_SELECTED) {
900 /* Try to perform paste on this bone. */
901 bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
902 if (pchan != nullptr) {
903 /* Keyframing tagging for successful paste, */
904 blender::animrig::autokeyframe_pchan(C, scene, ob, pchan, ks);
905 }
906 }
907 }
908 BKE_main_free(temp_bmain);
909
910 /* Update event for pose and deformation children. */
912
913 /* Recalculate paths if any of the bones have paths... */
916 }
917
918 /* Notifiers for updates, */
920
921 return OPERATOR_FINISHED;
922}
923
925{
926 PropertyRNA *prop;
927
928 /* identifiers */
929 ot->name = "Paste Pose";
930 ot->idname = "POSE_OT_paste";
931 ot->description = "Paste the stored pose on to the current pose";
932
933 /* API callbacks. */
934 ot->exec = pose_paste_exec;
935 ot->poll = ED_operator_posemode;
936
937 /* flag */
939
940 /* properties */
941 prop = RNA_def_boolean(ot->srna,
942 "flipped",
943 false,
944 "Flipped on X-Axis",
945 "Paste the stored pose flipped on to current pose");
947
948 RNA_def_boolean(ot->srna,
949 "selected_mask",
950 false,
951 "On Selected Only",
952 "Only paste the stored pose on to selected bones in the current pose");
953}
954
956
957/* -------------------------------------------------------------------- */
960
961/* clear scale of pose-channel */
963{
964 if ((pchan->protectflag & OB_LOCK_SCALEX) == 0) {
965 pchan->scale[0] = 1.0f;
966 }
967 if ((pchan->protectflag & OB_LOCK_SCALEY) == 0) {
968 pchan->scale[1] = 1.0f;
969 }
970 if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0) {
971 pchan->scale[2] = 1.0f;
972 }
973
974 pchan->ease1 = 0.0f;
975 pchan->ease2 = 0.0f;
976
977 copy_v3_fl(pchan->scale_in, 1.0f);
978 copy_v3_fl(pchan->scale_out, 1.0f);
979}
980/* Clear the scale. When X-mirror is enabled,
981 * also clear the scale of the mirrored pose channel. */
982static void pchan_clear_scale_with_mirrored(const bPose *pose, bPoseChannel *pchan)
983{
984 if (pose->flag & POSE_MIRROR_EDIT) {
985 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
986 if (pchan_mirror != nullptr) {
987 pchan_clear_scale(pchan_mirror);
988 }
989 }
990 pchan_clear_scale(pchan);
991}
992
993/* clear location of pose-channel */
994static void pchan_clear_loc(bPoseChannel *pchan)
995{
996 if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
997 pchan->loc[0] = 0.0f;
998 }
999 if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
1000 pchan->loc[1] = 0.0f;
1001 }
1002 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
1003 pchan->loc[2] = 0.0f;
1004 }
1005}
1006/* Clear the Location. When X-mirror is enabled,
1007 * also clear the location of the mirrored pose channel. */
1008static void pchan_clear_loc_with_mirrored(const bPose *pose, bPoseChannel *pchan)
1009{
1010 if (pose->flag & POSE_MIRROR_EDIT) {
1011 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
1012 if (pchan_mirror != nullptr) {
1013 pchan_clear_loc(pchan_mirror);
1014 }
1015 }
1016 pchan_clear_loc(pchan);
1017}
1018
1019/* clear rotation of pose-channel */
1021{
1023 /* check if convert to eulers for locking... */
1024 if (pchan->protectflag & OB_LOCK_ROT4D) {
1025 /* perform clamping on a component by component basis */
1026 if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1027 if ((pchan->protectflag & OB_LOCK_ROTW) == 0) {
1028 pchan->rotAngle = 0.0f;
1029 }
1030 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1031 pchan->rotAxis[0] = 0.0f;
1032 }
1033 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1034 pchan->rotAxis[1] = 0.0f;
1035 }
1036 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1037 pchan->rotAxis[2] = 0.0f;
1038 }
1039
1040 /* check validity of axis - axis should never be 0,0,0
1041 * (if so, then we make it rotate about y). */
1042 if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) &&
1043 IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
1044 {
1045 pchan->rotAxis[1] = 1.0f;
1046 }
1047 }
1048 else if (pchan->rotmode == ROT_MODE_QUAT) {
1049 if ((pchan->protectflag & OB_LOCK_ROTW) == 0) {
1050 pchan->quat[0] = 1.0f;
1051 }
1052 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1053 pchan->quat[1] = 0.0f;
1054 }
1055 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1056 pchan->quat[2] = 0.0f;
1057 }
1058 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1059 pchan->quat[3] = 0.0f;
1060 }
1061 }
1062 else {
1063 /* the flag may have been set for the other modes, so just ignore the extra flag... */
1064 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1065 pchan->eul[0] = 0.0f;
1066 }
1067 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1068 pchan->eul[1] = 0.0f;
1069 }
1070 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1071 pchan->eul[2] = 0.0f;
1072 }
1073 }
1074 }
1075 else {
1076 /* perform clamping using euler form (3-components) */
1077 float eul[3], oldeul[3], quat1[4] = {0};
1078 float qlen = 0.0f;
1079
1080 if (pchan->rotmode == ROT_MODE_QUAT) {
1081 qlen = normalize_qt_qt(quat1, pchan->quat);
1082 quat_to_eul(oldeul, quat1);
1083 }
1084 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1085 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
1086 }
1087 else {
1088 copy_v3_v3(oldeul, pchan->eul);
1089 }
1090
1091 eul[0] = eul[1] = eul[2] = 0.0f;
1092
1093 if (pchan->protectflag & OB_LOCK_ROTX) {
1094 eul[0] = oldeul[0];
1095 }
1096 if (pchan->protectflag & OB_LOCK_ROTY) {
1097 eul[1] = oldeul[1];
1098 }
1099 if (pchan->protectflag & OB_LOCK_ROTZ) {
1100 eul[2] = oldeul[2];
1101 }
1102
1103 if (pchan->rotmode == ROT_MODE_QUAT) {
1104 eul_to_quat(pchan->quat, eul);
1105
1106 /* restore original quat size */
1107 mul_qt_fl(pchan->quat, qlen);
1108
1109 /* quaternions flip w sign to accumulate rotations correctly */
1110 if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) ||
1111 (quat1[0] > 0.0f && pchan->quat[0] < 0.0f))
1112 {
1113 mul_qt_fl(pchan->quat, -1.0f);
1114 }
1115 }
1116 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1118 }
1119 else {
1120 copy_v3_v3(pchan->eul, eul);
1121 }
1122 }
1123 } /* Duplicated in source/blender/editors/object/object_transform.cc */
1124 else {
1125 if (pchan->rotmode == ROT_MODE_QUAT) {
1126 unit_qt(pchan->quat);
1127 }
1128 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1129 /* by default, make rotation of 0 radians around y-axis (roll) */
1130 unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
1131 }
1132 else {
1133 zero_v3(pchan->eul);
1134 }
1135 }
1136
1137 /* Clear also Bendy Bone stuff - Roll is obvious,
1138 * but Curve X/Y stuff is also kind of rotational in nature... */
1139 pchan->roll1 = 0.0f;
1140 pchan->roll2 = 0.0f;
1141
1142 pchan->curve_in_x = 0.0f;
1143 pchan->curve_in_z = 0.0f;
1144 pchan->curve_out_x = 0.0f;
1145 pchan->curve_out_z = 0.0f;
1146}
1147/* Clear the rotation. When X-mirror is enabled,
1148 * also clear the rotation of the mirrored pose channel. */
1149static void pchan_clear_rot_with_mirrored(const bPose *pose, bPoseChannel *pchan)
1150{
1151 if (pose->flag & POSE_MIRROR_EDIT) {
1152 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
1153 if (pchan_mirror != nullptr) {
1154 pchan_clear_rot(pchan_mirror);
1155 }
1156 }
1157 pchan_clear_rot(pchan);
1158}
1159
1160/* clear loc/rot/scale of pose-channel */
1161static void pchan_clear_transforms(const bPose *pose, bPoseChannel *pchan)
1162{
1163 pchan_clear_loc_with_mirrored(pose, pchan);
1164 pchan_clear_rot_with_mirrored(pose, pchan);
1166}
1167
1168/* --------------- */
1169
1170/* generic exec for clear-pose operators */
1172 wmOperator *op,
1173 void (*clear_func)(const bPose *,
1174 bPoseChannel *),
1175 const char default_ksName[])
1176{
1178 Scene *scene = CTX_data_scene(C);
1179 bool changed_multi = false;
1180
1181 /* sanity checks */
1182 if (ELEM(nullptr, clear_func, default_ksName)) {
1183 BKE_report(op->reports,
1184 RPT_ERROR,
1185 "Programming error: missing clear transform function or keying set name");
1186 return OPERATOR_CANCELLED;
1187 }
1188
1189 /* only clear relevant transforms for selected bones */
1190 ViewLayer *view_layer = CTX_data_view_layer(C);
1191 View3D *v3d = CTX_wm_view3d(C);
1192 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
1193 /* XXX: UGLY HACK (for auto-key + clear transforms). */
1194 Object *ob_eval = DEG_get_evaluated(depsgraph, ob_iter);
1196 bool changed = false;
1197
1199 /* run provided clearing function */
1200 clear_func(ob_iter->pose, pchan);
1201 changed = true;
1202
1203 /* do auto-keyframing as appropriate */
1204 if (blender::animrig::autokeyframe_cfra_can_key(scene, &ob_iter->id)) {
1205 /* tag for autokeying later */
1207 sources, &ob_iter->id, &RNA_PoseBone, pchan);
1208
1209#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */
1210 bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
1211 clear_func(ob_iter->pose, pchan_eval);
1212#endif
1213 }
1214 }
1216
1217 if (changed) {
1218 changed_multi = true;
1219
1220 /* perform autokeying on the bones if needed */
1221 if (!sources.is_empty()) {
1222 /* get KeyingSet to use */
1223 KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, default_ksName);
1224
1225 /* insert keyframes */
1227 C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra));
1228
1229 /* now recalculate paths */
1230 if (ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
1232 }
1233 }
1234
1236
1237 /* NOTE: notifier might evolve. */
1239 }
1240 }
1242
1243 return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1244}
1245
1247
1248/* -------------------------------------------------------------------- */
1251
1257
1259{
1260 /* identifiers */
1261 ot->name = "Clear Pose Scale";
1262 ot->idname = "POSE_OT_scale_clear";
1263 ot->description = "Reset scaling of selected bones to their default values";
1264
1265 /* API callbacks. */
1266 ot->exec = pose_clear_scale_exec;
1267 ot->poll = ED_operator_posemode;
1268
1269 /* flags */
1270 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1271}
1272
1274
1275/* -------------------------------------------------------------------- */
1278
1284
1286{
1287 /* identifiers */
1288 ot->name = "Clear Pose Rotation";
1289 ot->idname = "POSE_OT_rot_clear";
1290 ot->description = "Reset rotations of selected bones to their default values";
1291
1292 /* API callbacks. */
1293 ot->exec = pose_clear_rot_exec;
1294 ot->poll = ED_operator_posemode;
1295
1296 /* flags */
1297 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1298}
1299
1301
1302/* -------------------------------------------------------------------- */
1305
1311
1313{
1314 /* identifiers */
1315 ot->name = "Clear Pose Location";
1316 ot->idname = "POSE_OT_loc_clear";
1317 ot->description = "Reset locations of selected bones to their default values";
1318
1319 /* API callbacks. */
1320 ot->exec = pose_clear_loc_exec;
1321 ot->poll = ED_operator_posemode;
1322
1323 /* flags */
1324 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1325}
1326
1328
1329/* -------------------------------------------------------------------- */
1332
1338
1340{
1341 /* identifiers */
1342 ot->name = "Clear Pose Transforms";
1343 ot->idname = "POSE_OT_transforms_clear";
1344 ot->description =
1345 "Reset location, rotation, and scaling of selected bones to their default values";
1346
1347 /* API callbacks. */
1349 ot->poll = ED_operator_posemode;
1350
1351 /* flags */
1352 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1353}
1354
1356
1357/* -------------------------------------------------------------------- */
1360
1362{
1363 ViewLayer *view_layer = CTX_data_view_layer(C);
1364 View3D *v3d = CTX_wm_view3d(C);
1365 Scene *scene = CTX_data_scene(C);
1368 depsgraph, float(scene->r.cfra));
1369 const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
1370
1371 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
1372 if ((ob->adt) && (ob->adt->action)) {
1373 /* XXX: this is just like this to avoid contaminating anything else;
1374 * just pose values should change, so this should be fine
1375 */
1376 bPose *dummyPose = nullptr;
1377 Object workob{};
1378
1379 /* execute animation step for current frame using a dummy copy of the pose */
1380 BKE_pose_copy_data(&dummyPose, ob->pose, false);
1381
1382 STRNCPY_UTF8(workob.id.name, "OB<ClearTfmWorkOb>");
1383 workob.type = OB_ARMATURE;
1384 workob.data = ob->data;
1385 workob.adt = ob->adt;
1386 workob.pose = dummyPose;
1387
1389 &workob.id, workob.adt, &anim_eval_context, ADT_RECALC_ANIM, false);
1390
1391 /* Copy back values, but on selected bones only. */
1392 LISTBASE_FOREACH (bPoseChannel *, pchan, &dummyPose->chanbase) {
1393 pose_bone_do_paste(ob, pchan, only_select, false);
1394 }
1395
1396 /* free temp data - free manually as was copied without constraints */
1397 LISTBASE_FOREACH (bPoseChannel *, pchan, &dummyPose->chanbase) {
1398 if (pchan->prop) {
1399 IDP_FreeProperty(pchan->prop);
1400 }
1401 if (pchan->system_properties) {
1402 IDP_FreeProperty(pchan->system_properties);
1403 }
1404 }
1405
1406 /* was copied without constraints */
1407 BLI_freelistN(&dummyPose->chanbase);
1408 MEM_freeN(dummyPose);
1409 }
1410 else {
1411 /* No animation, so just reset to the rest pose. */
1412 BKE_pose_rest(ob->pose, only_select);
1413 }
1414
1415 /* notifiers and updates */
1418 }
1420
1421 return OPERATOR_FINISHED;
1422}
1423
1425{
1426 /* identifiers */
1427 ot->name = "Clear User Transforms";
1428 ot->idname = "POSE_OT_user_transforms_clear";
1429 ot->description = "Reset pose bone transforms to keyframed state";
1430
1431 /* callbacks */
1433 ot->poll = ED_operator_posemode;
1434
1435 /* flags */
1436 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1437
1438 /* properties */
1439 RNA_def_boolean(ot->srna, "only_selected", true, "Only Selected", "Only visible/selected bones");
1440}
1441
Functions to deal with Armatures.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
Functions to insert, delete or modify keyframes.
Functionality to interact with keying sets.
static constexpr const char * ANIM_KS_ROTATION_ID
static constexpr const char * ANIM_KS_SCALING_ID
static constexpr const char * ANIM_KS_WHOLE_CHARACTER_ID
static constexpr const char * ANIM_KS_LOC_ROT_SCALE_ID
static constexpr const char * ANIM_KS_LOCATION_ID
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
bPoseChannel * BKE_pose_channel_get_mirrored(const bPose *pose, const char *name) ATTR_WARN_UNUSED_RESULT
void BKE_pose_copy_data(bPose **dst, const bPose *src, bool copy_constraints)
void BKE_pose_rest(bPose *pose, bool selected_bones_only)
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:738
@ ADT_RECALC_ANIM
void BKE_animsys_evaluate_animdata(struct ID *id, struct AnimData *adt, const struct AnimationEvalContext *anim_eval_context, eAnimData_Recalc recalc, bool flush_to_original)
const char * BKE_tempdir_base() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:1243
bArmature * BKE_armature_from_object(Object *ob)
void BKE_bone_parent_transform_clear(BoneParentTransform *bpt)
void BKE_bone_parent_transform_combine(const BoneParentTransform *in1, const BoneParentTransform *in2, BoneParentTransform *result)
void BKE_bone_parent_transform_invert(BoneParentTransform *bpt)
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_END
void BKE_bone_parent_transform_apply(const BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4])
void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3])
void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag, int inherit_scale_mode, const float offs_bone[4][4], const float parent_arm_mat[4][4], const float parent_pose_mat[4][4], BoneParentTransform *r_bpt)
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan)
void BKE_armature_mat_pose_to_bone(const bPoseChannel *pchan, const float inmat[4][4], float outmat[4][4])
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports, uint64_t id_types_mask)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
#define CTX_DATA_COUNT(C, member)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
bool CTX_data_selected_pose_bones(const bContext *C, blender::Vector< PointerRNA > *list)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1251
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:863
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) ATTR_NONNULL()
Definition idprop.cc:585
#define FOREACH_OBJECT_IN_MODE_END
Definition BKE_layer.hh:382
#define FOREACH_OBJECT_IN_MODE_BEGIN(_scene, _view_layer, _v3d, _object_type, _object_mode, _instance)
Definition BKE_layer.hh:377
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:892
General operations, lookup, etc. for blender objects.
blender::float4x4 BKE_object_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
Object * BKE_object_pose_armature_get(Object *ob)
bool BKE_object_obdata_is_libdata(const Object *ob)
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
bool invert_m4(float mat[4][4])
void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void unit_m4(float m[4][4])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
@ EULER_ORDER_DEFAULT
void quat_to_eulO(float e[3], short order, const float q[4])
float normalize_qt(float q[4])
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], short order)
void mul_qt_fl(float q[4], float f)
void unit_qt(float q[4])
void eulO_to_quat(float q[4], const float e[3], short order)
void eul_to_quat(float quat[4], const float eul[3])
void quat_to_eul(float eul[3], const float quat[4])
float normalize_qt_qt(float r[4], const float q[4])
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
void axis_angle_to_eulO(float eul[3], short order, const float axis[3], float angle)
void unit_axis_angle(float axis[3], float *angle)
void copy_qt_qt(float q[4], const float a[4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
#define FILE_MAX
#define BLI_path_join(...)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define STRNCPY_UTF8(dst, src)
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 ELEM(...)
#define IS_EQF(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
#define ID_IS_PACKED(_id)
Definition DNA_ID.h:700
#define FILTER_ID_OB
Definition DNA_ID.h:1214
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ MOTIONPATH_BAKE_HAS_PATHS
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ POSE_SELECTED
@ POSE_MIRROR_EDIT
#define MAXBONENAME
@ BONE_CONNECTED
@ CONSTRAINT_TYPE_STRETCHTO
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ PARBONE
@ OB_ARMATURE
@ OB_LOCK_ROTZ
@ OB_LOCK_ROT4D
@ OB_LOCK_SCALEZ
@ OB_LOCK_ROTX
@ OB_LOCK_SCALEX
@ OB_LOCK_ROTW
@ OB_LOCK_LOCY
@ OB_LOCK_LOCZ
@ OB_LOCK_ROTY
@ OB_LOCK_SCALEY
@ OB_LOCK_LOCX
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ POSE_PATH_CALC_RANGE_FULL
bool ED_operator_posemode(bContext *C)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_POSE
Definition WM_types.hh:458
#define ND_TRANSFORM
Definition WM_types.hh:456
#define NC_OBJECT
Definition WM_types.hh:379
EditBone * ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
void ED_armature_edit_free(bArmature *arm)
void ED_armature_from_edit(Main *bmain, bArmature *arm)
void ED_armature_to_edit(bArmature *arm)
BPy_StructRNA * depsgraph
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr const T * begin() const
Definition BLI_span.hh:220
bool is_empty() const
ID * id_add(const ID *id, IDAddOptions options, blender::FunctionRef< IDAddOperations(LibraryIDLinkCallbackData *cb_data, IDAddOptions options)> dependencies_filter_cb=nullptr)
nullptr float
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
void relative_keyingset_add_source(blender::Vector< PointerRNA > &sources, ID *id, StructRNA *srna, void *data)
bool bone_is_visible(const bArmature *armature, const Bone *bone)
bool bone_is_selected(const bArmature *armature, const Bone *bone)
KeyingSet * get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
int apply_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset, ModifyKeyMode mode, float cfra)
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
Definition pose_edit.cc:152
static void pchan_clear_scale_with_mirrored(const bPose *pose, bPoseChannel *pchan)
static wmOperatorStatus pose_visual_transform_apply_exec(bContext *C, wmOperator *)
void POSE_OT_armature_apply(wmOperatorType *ot)
static void pchan_clear_transforms(const bPose *pose, bPoseChannel *pchan)
void POSE_OT_transforms_clear(wmOperatorType *ot)
static void applyarmature_reset_bone_constraints(const bPoseChannel *pchan)
static wmOperatorStatus pose_clear_scale_exec(bContext *C, wmOperator *op)
void POSE_OT_paste(wmOperatorType *ot)
static void applyarmature_set_edit_position(EditBone *curbone, const float pose_mat[4][4], const float new_tail[3], float r_new_arm_mat[4][4])
static wmOperatorStatus pose_copy_exec(bContext *C, wmOperator *op)
static void applyarmature_process_selected_recursive(bArmature *arm, bPose *pose, bPose *pose_eval, Bone *bone, blender::Span< PointerRNA > selected, ApplyArmature_ParentState *pstate)
static void pose_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
static void pchan_clear_scale(bPoseChannel *pchan)
void POSE_OT_visual_transform_apply(wmOperatorType *ot)
static wmOperatorStatus apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
static void applyarmature_reset_bone_constraint(const bConstraint *constraint)
static wmOperatorStatus pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
static void pchan_clear_loc_with_mirrored(const bPose *pose, bPoseChannel *pchan)
static wmOperatorStatus pose_clear_transform_generic_exec(bContext *C, wmOperator *op, void(*clear_func)(const bPose *, bPoseChannel *), const char default_ksName[])
static wmOperatorStatus pose_clear_loc_exec(bContext *C, wmOperator *op)
static bPoseChannel * pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bool selOnly, const bool flip)
static void applyarmature_reset_constraints(bPose *pose, const bool use_selected)
static void pchan_clear_rot(bPoseChannel *pchan)
void POSE_OT_copy(wmOperatorType *ot)
void POSE_OT_rot_clear(wmOperatorType *ot)
static void applyarmature_adjust_edit_position(bArmature *arm, bPoseChannel *pchan, const float delta_mat[4][4], float r_new_arm_mat[4][4])
static wmOperatorStatus pose_paste_exec(bContext *C, wmOperator *op)
static void applyarmature_transfer_properties(EditBone *curbone, bPoseChannel *pchan, const bPoseChannel *pchan_eval)
static void apply_armature_pose2bones_ui(bContext *C, wmOperator *op)
void POSE_OT_loc_clear(wmOperatorType *ot)
static void pchan_clear_loc(bPoseChannel *pchan)
void POSE_OT_scale_clear(wmOperatorType *ot)
static wmOperatorStatus pose_clear_transforms_exec(bContext *C, wmOperator *op)
static wmOperatorStatus pose_clear_rot_exec(bContext *C, wmOperator *op)
void POSE_OT_user_transforms_clear(wmOperatorType *ot)
static void pchan_clear_rot_with_mirrored(const bPose *pose, bPoseChannel *pchan)
const char * name
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
bAction * action
struct Bone * parent
char name[64]
char inherit_scale_mode
float arm_mat[4][4]
ListBase childbase
float curve_out_z
float scale_in[3]
float ease2
float roll1
float tail[3]
float roll2
float curve_in_x
float curve_in_z
float ease1
float scale_out[3]
float curve_out_x
float head[3]
char name[258]
Definition DNA_ID.h:432
void * first
char filepath[1024]
Definition BKE_main.hh:179
ListBase objects
Definition BKE_main.hh:280
struct bPose * pose
struct AnimData * adt
struct RenderData r
ListBase * edbo
IDProperty * prop
struct Bone * bone
struct bPoseChannel * parent
IDProperty * system_properties
float pose_mat[4][4]
ListBase chanbase
bAnimVizSettings avs
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
StructRNA * srna
Definition WM_types.hh:1127
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237