Blender V4.3
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
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_blenlib.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_string_utils.hh"
22
23#include "BKE_action.hh"
24#include "BKE_animsys.h"
25#include "BKE_appdir.hh"
26#include "BKE_armature.hh"
28#include "BKE_blendfile.hh"
29#include "BKE_context.hh"
30#include "BKE_idprop.hh"
31#include "BKE_layer.hh"
32#include "BKE_lib_query.hh"
33#include "BKE_main.hh"
34#include "BKE_object.hh"
35#include "BKE_report.hh"
36
37#include "DEG_depsgraph.hh"
39
40#include "RNA_access.hh"
41#include "RNA_define.hh"
42#include "RNA_prototypes.hh"
43
44#include "WM_api.hh"
45#include "WM_types.hh"
46
47#include "ED_armature.hh"
48#include "ED_keyframing.hh"
49#include "ED_screen.hh"
50
52#include "ANIM_keyframing.hh"
53#include "ANIM_keyingsets.hh"
54
55#include "UI_interface.hh"
56#include "UI_resources.hh"
57
58#include "armature_intern.hh"
59
60/* -------------------------------------------------------------------- */
64static void pose_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
65{
66 BLI_path_join(filepath, filepath_maxncpy, BKE_tempdir_base(), "copybuffer_pose.blend");
67}
68
71/* -------------------------------------------------------------------- */
75/* helper for apply_armature_pose2bones - fixes parenting of objects
76 * that are bone-parented to armature */
77static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
78{
79 /* Depsgraph has been ensured to be evaluated at the beginning of the operator.
80 *
81 * Must not evaluate depsgraph here yet, since this will ruin object matrix which we want to
82 * preserve after other changes has been done in the operator.
83 *
84 * TODO(sergey): This seems very similar to `ignore_parent_tx()`, which was now ensured to work
85 * quite reliably. Can we de-duplicate the code? Or at least verify we don't need an extra logic
86 * in this function. */
88 Main *bmain = CTX_data_main(C);
89
90 /* go through all objects in database */
91 for (Object *ob = static_cast<Object *>(bmain->objects.first); ob;
92 ob = static_cast<Object *>(ob->id.next))
93 {
94 /* if parent is bone in this armature, apply corrections */
95 if ((ob->parent == armob) && (ob->partype == PARBONE)) {
96 /* apply current transform from parent (not yet destroyed),
97 * then calculate new parent inverse matrix
98 */
99 BKE_object_apply_mat4(ob, ob->object_to_world().ptr(), false, false);
100
101 invert_m4_m4(ob->parentinv, BKE_object_calc_parent(depsgraph, scene, ob).ptr());
102 }
103 }
104}
105
106/* Sets the bone head, tail and roll to match the supplied parameters. */
108 const float pose_mat[4][4],
109 const float new_tail[3],
110 float r_new_arm_mat[4][4])
111{
112 /* Simply copy the head/tail values from pchan over to curbone. */
113 copy_v3_v3(curbone->head, pose_mat[3]);
114 copy_v3_v3(curbone->tail, new_tail);
115
116 /* Fix roll:
117 * 1. find auto-calculated roll value for this bone now
118 * 2. remove this from the 'visual' y-rotation
119 */
120 {
121 float premat[3][3], pmat[3][3];
122 float delta[3];
123
124 /* Obtain new auto y-rotation. */
125 sub_v3_v3v3(delta, curbone->tail, curbone->head);
126
127 copy_m3_m4(pmat, pose_mat);
128 mat3_vec_to_roll(pmat, delta, &curbone->roll);
129
130 /* Compute new rest pose matrix if requested. */
131 if (r_new_arm_mat) {
132 vec_roll_to_mat3(delta, curbone->roll, premat);
133 copy_m4_m3(r_new_arm_mat, premat);
134 copy_v3_v3(r_new_arm_mat[3], pose_mat[3]);
135 }
136 }
137}
138
139/* Copy properties over from pchan to curbone and reset channels. */
141 bPoseChannel *pchan,
142 const bPoseChannel *pchan_eval)
143{
144 /* Combine pose and rest values for bendy bone settings,
145 * then clear the pchan values (so we don't get a double-up).
146 */
147 if (pchan->bone->segments > 1) {
148 /* Combine rest/pose values. */
149 curbone->curve_in_x += pchan_eval->curve_in_x;
150 curbone->curve_in_z += pchan_eval->curve_in_z;
151 curbone->curve_out_x += pchan_eval->curve_out_x;
152 curbone->curve_out_z += pchan_eval->curve_out_z;
153 curbone->roll1 += pchan_eval->roll1;
154 curbone->roll2 += pchan_eval->roll2;
155 curbone->ease1 += pchan_eval->ease1;
156 curbone->ease2 += pchan_eval->ease2;
157
158 mul_v3_v3(curbone->scale_in, pchan_eval->scale_in);
159 mul_v3_v3(curbone->scale_out, pchan_eval->scale_out);
160
161 /* Reset pose values. */
162 pchan->curve_in_x = pchan->curve_out_x = 0.0f;
163 pchan->curve_in_z = pchan->curve_out_z = 0.0f;
164 pchan->roll1 = pchan->roll2 = 0.0f;
165 pchan->ease1 = pchan->ease2 = 0.0f;
166
167 copy_v3_fl(pchan->scale_in, 1.0f);
168 copy_v3_fl(pchan->scale_out, 1.0f);
169 }
170
171 /* Clear transform values for pchan. */
172 zero_v3(pchan->loc);
173 zero_v3(pchan->eul);
174 unit_qt(pchan->quat);
175 unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
176 pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
177}
178
179/* Adjust the current edit position of the bone using the pose space matrix. */
181 bPoseChannel *pchan,
182 const float delta_mat[4][4],
183 float r_new_arm_mat[4][4])
184{
185 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
186 float delta[3], new_tail[3], premat[3][3], new_pose[4][4];
187
188 /* Current orientation matrix. */
189 sub_v3_v3v3(delta, curbone->tail, curbone->head);
190 vec_roll_to_mat3(delta, curbone->roll, premat);
191
192 /* New location and orientation. */
193 mul_m4_m4m3(new_pose, delta_mat, premat);
194 mul_v3_m4v3(new_pose[3], delta_mat, curbone->head);
195 mul_v3_m4v3(new_tail, delta_mat, curbone->tail);
196
197 applyarmature_set_edit_position(curbone, new_pose, new_tail, r_new_arm_mat);
198}
199
200/* Data about parent position for Apply To Selected mode. */
203
204 /* New rest position of the bone with scale included. */
205 float new_rest_mat[4][4];
206 /* New arm_mat of the bone == new_rest_mat without scale. */
207 float new_arm_mat[4][4];
208};
209
210/* Recursive walk for Apply To Selected mode; pstate nullptr unless child of an applied bone. */
212 bPose *pose,
213 bPose *pose_eval,
214 Bone *bone,
217{
218 bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
219 const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
220
221 if (!pchan || !pchan_eval) {
222 return;
223 }
224
225 ApplyArmature_ParentState new_pstate{};
226 new_pstate.bone = bone;
227
228 if (std::find_if(selected.begin(), selected.end(), [&](const PointerRNA &ptr) {
229 return ptr.data == pchan;
230 }) != selected.end())
231 {
232 /* SELECTED BONE: Snap to final pose transform minus un-applied parent effects.
233 *
234 * I.e. bone position with accumulated parent effects but no local
235 * transformation will match the original final pose_mat.
236 *
237 * Pose channels are reset as expected.
238 */
239 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
240 BoneParentTransform invparent;
241 float new_tail[3];
242
243 if (pchan->parent) {
244 BoneParentTransform old_bpt, new_bpt;
245 float offs_bone[4][4];
246
247 /* Parent effects on the bone transform that have to be removed. */
248 BKE_bone_offset_matrix_get(bone, offs_bone);
250 bone->inherit_scale_mode,
251 offs_bone,
252 bone->parent->arm_mat,
253 pchan_eval->parent->pose_mat,
254 &old_bpt);
255
256 /* Applied parent effects that have to be kept, if any. */
257 float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat;
259 bone->inherit_scale_mode,
260 offs_bone,
261 bone->parent->arm_mat,
262 new_parent_pose,
263 &new_bpt);
264
266 BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
267 }
268 else {
270 }
271
272 /* Apply change without inherited unapplied parent transformations. */
273 BKE_bone_parent_transform_apply(&invparent, pchan_eval->pose_mat, new_pstate.new_rest_mat);
274
275 copy_v3_fl3(new_tail, 0.0, bone->length, 0.0);
276 mul_m4_v3(new_pstate.new_rest_mat, new_tail);
277
279 curbone, new_pstate.new_rest_mat, new_tail, new_pstate.new_arm_mat);
280 applyarmature_transfer_properties(curbone, pchan, pchan_eval);
281
282 pstate = &new_pstate;
283 }
284 else if (pstate) {
285 /* UNSELECTED CHILD OF SELECTED: Include applied parent effects.
286 *
287 * The inherited transform of applied (selected) bones is baked
288 * into the rest pose so that the final bone position doesn't
289 * change.
290 *
291 * Pose channels are not changed, with the exception of the inherited
292 * applied parent scale being baked into the location pose channel.
293 */
295 float offs_bone[4][4], delta[4][4], old_chan_loc[3];
296
297 /* Include applied parent effects. */
298 BKE_bone_offset_matrix_get(bone, offs_bone);
300 bone->inherit_scale_mode,
301 offs_bone,
302 pstate->bone->arm_mat,
303 pstate->new_rest_mat,
304 &bpt);
305
306 unit_m4(new_pstate.new_rest_mat);
307 BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
308
309 /* Bone location channel in pose space relative to bone head. */
310 mul_v3_mat3_m4v3(old_chan_loc, bpt.loc_mat, pchan_eval->loc);
311
312 /* Apply the change to the rest bone position. */
313 invert_m4_m4(delta, bone->arm_mat);
314 mul_m4_m4m4(delta, new_pstate.new_rest_mat, delta);
315
316 applyarmature_adjust_edit_position(arm, pchan, delta, new_pstate.new_arm_mat);
317
318 /* Location pose channel has to be updated, because it is affected
319 * by parent scaling, and the rest pose has no scale by definition. */
320 if (!(bone->flag & BONE_CONNECTED) && !is_zero_v3(old_chan_loc)) {
321 float inv_parent_arm[4][4];
322
323 /* Compute the channel coordinate space matrices for the new rest state. */
324 invert_m4_m4(inv_parent_arm, pstate->new_arm_mat);
325 mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat);
327 bone->inherit_scale_mode,
328 offs_bone,
329 pstate->new_arm_mat,
330 pstate->new_arm_mat,
331 &bpt);
332
333 /* Re-apply the location to keep the final effect. */
334 invert_m4(bpt.loc_mat);
335 mul_v3_mat3_m4v3(pchan->loc, bpt.loc_mat, old_chan_loc);
336 }
337
338 pstate = &new_pstate;
339 }
340
341 LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
342 applyarmature_process_selected_recursive(arm, pose, pose_eval, child, selected, pstate);
343 }
344}
345
346/* Reset bone constraint so that it is correct after the pose has been applied. */
348{
349 /* TODO(Sybren): This function needs too much knowledge of the internals of specific constraints.
350 * When it is extended with one or two more constraints, move the functionality into a
351 * bConstraintTypeInfo callback function. */
352 switch (constraint->type) {
354 bStretchToConstraint *stretch_to = (bStretchToConstraint *)constraint->data;
355 stretch_to->orglength = 0.0f; /* Force recalculation on next evaluation. */
356 break;
357 }
358 default:
359 /* Most constraints don't need resetting. */
360 break;
361 }
362}
363
364/* Reset bone constraints of the given pose channel so that they are correct after the pose has
365 * been applied. */
367{
368 LISTBASE_FOREACH (bConstraint *, constraint, &pchan->constraints) {
370 }
371}
372
373/* Reset all (or only selected) bone constraints so that they are correct after the pose has been
374 * applied. */
375static void applyarmature_reset_constraints(bPose *pose, const bool use_selected)
376{
377 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
378 BLI_assert(pchan->bone != nullptr);
379 if (use_selected && (pchan->bone->flag & BONE_SELECTED) == 0) {
380 continue;
381 }
383 }
384}
385
386/* Set the current pose as the rest-pose. */
388{
389 Main *bmain = CTX_data_main(C);
391 Scene *scene = CTX_data_scene(C);
392 /* must be active object, not edit-object */
394 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
396 bPose *pose;
397 blender::Vector<PointerRNA> selected_bones;
398
399 const bool use_selected = RNA_boolean_get(op->ptr, "selected");
400
401 /* don't check if editmode (should be done by caller) */
402 if (ob->type != OB_ARMATURE) {
403 return OPERATOR_CANCELLED;
404 }
406 BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature");
407 return OPERATOR_CANCELLED;
408 }
409
410 /* helpful warnings... */
411 /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
412 if (ob->adt && ob->adt->action) {
415 "Actions on this armature will be destroyed by this new rest pose as the "
416 "transforms stored are relative to the old rest pose");
417 }
418
419 /* Find selected bones before switching to edit mode. */
420 if (use_selected) {
421 CTX_data_selected_pose_bones(C, &selected_bones);
422
423 if (selected_bones.is_empty()) {
424 return OPERATOR_CANCELLED;
425 }
426 }
427
428 /* Get edit-bones of active armature to alter. */
430
431 /* Get pose of active object and move it out of pose-mode. */
432 pose = ob->pose;
433
434 if (use_selected) {
435 /* The selected only mode requires a recursive walk to handle parent-child relations. */
436 LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
438 arm, pose, ob_eval->pose, bone, selected_bones, nullptr);
439 }
440 }
441 else {
442 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
443 const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
444 EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
445
447 curbone, pchan_eval->pose_mat, pchan_eval->pose_tail, nullptr);
448 applyarmature_transfer_properties(curbone, pchan, pchan_eval);
449 }
450 }
451
452 /* Convert edit-bones back to bones, and then free the edit-data. */
453 ED_armature_from_edit(bmain, arm);
455
456 /* Flush positions of pose-bones. */
457 BKE_pose_where_is(depsgraph, scene, ob);
458
459 /* fix parenting of objects which are bone-parented */
460 applyarmature_fix_boneparents(C, scene, ob);
461
462 /* For the affected bones, reset specific constraints that are now known to be invalid. */
463 applyarmature_reset_constraints(pose, use_selected);
464
465 /* NOTE: notifier might evolve. */
468
469 return OPERATOR_FINISHED;
470}
471
473{
474 uiLayout *layout = op->layout;
476
478
479 uiItemR(layout, &ptr, "selected", UI_ITEM_NONE, nullptr, ICON_NONE);
480}
481
483{
484 /* identifiers */
485 ot->name = "Apply Pose as Rest Pose";
486 ot->idname = "POSE_OT_armature_apply";
487 ot->description = "Apply the current pose as the new rest pose";
488
489 /* callbacks */
493
494 /* flags */
496
498 "selected",
499 false,
500 "Selected Only",
501 "Only apply the selected bones (with propagation to children)");
502}
503
506/* -------------------------------------------------------------------- */
513{
514 const Scene *scene = CTX_data_scene(C);
515 ViewLayer *view_layer = CTX_data_view_layer(C);
516 View3D *v3d = CTX_wm_view3d(C);
517
518 /* Needed to ensure #bPoseChannel.pose_mat are up to date. */
520
521 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
522 const bArmature *arm = static_cast<const bArmature *>(ob->data);
523
524 int chanbase_len = BLI_listbase_count(&ob->pose->chanbase);
525 /* Storage for the calculated matrices to prevent reading from modified values.
526 * NOTE: this could be avoided if children were always calculated before parents
527 * however ensuring this is involved and doesn't give any significant advantage. */
528 struct XFormArray {
529 float matrix[4][4];
530 bool is_set;
531 } *pchan_xform_array = static_cast<XFormArray *>(
532 MEM_mallocN(sizeof(*pchan_xform_array) * chanbase_len, __func__));
533 bool changed = false;
534
535 int i;
536 LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) {
537 if (!((pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone))) {
538 pchan_xform_array[i].is_set = false;
539 continue;
540 }
541
542 /* `chan_mat` already contains the delta transform from rest pose to pose-mode pose
543 * as that is baked into there so that B-Bones will work. Once we've set this as the
544 * new raw-transform components, don't recalculate the poses yet, otherwise IK result will
545 * change, thus changing the result we may be trying to record. */
546
547 /* NOTE: For some reason `pchan->chan_mat` can't be used here as it gives odd
548 * rotation/offset, see #38251.
549 * Using `pchan->pose_mat` and bringing it back in bone space seems to work as expected!
550 * This matches how visual key-framing works. */
551 BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, pchan_xform_array[i].matrix);
552 pchan_xform_array[i].is_set = true;
553 changed = true;
554 }
555
556 if (changed) {
557 /* Perform separately to prevent feedback loop. */
558 LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) {
559 if (!pchan_xform_array[i].is_set) {
560 continue;
561 }
562 BKE_pchan_apply_mat4(pchan, pchan_xform_array[i].matrix, true);
563 }
564
566
567 /* NOTE: notifier might evolve. */
569 }
570
571 MEM_freeN(pchan_xform_array);
572 }
574
575 return OPERATOR_FINISHED;
576}
577
579{
580 /* identifiers */
581 ot->name = "Apply Visual Transform to Pose";
582 ot->idname = "POSE_OT_visual_transform_apply";
583 ot->description = "Apply final constrained position of pose bones to their transform";
584
585 /* callbacks */
588
589 /* flags */
591}
592
595/* -------------------------------------------------------------------- */
599/* This function is used to indicate that a bone is selected
600 * and needs to be included in copy buffer (used to be for inserting keys)
601 */
602static void set_pose_keys(Object *ob)
603{
604 bArmature *arm = static_cast<bArmature *>(ob->data);
605
606 if (ob->pose) {
607 LISTBASE_FOREACH (bPoseChannel *, chan, &ob->pose->chanbase) {
608 Bone *bone = chan->bone;
609 if ((bone) && (bone->flag & BONE_SELECTED) && ANIM_bone_in_visible_collection(arm, bone)) {
610 chan->flag |= POSE_KEY;
611 }
612 else {
613 chan->flag &= ~POSE_KEY;
614 }
615 }
616 }
617}
618
629 bPoseChannel *chan,
630 const bool selOnly,
631 const bool flip)
632{
633 char name[MAXBONENAME];
634
635 /* get the name - if flipping, we must flip this first */
636 if (flip) {
637 BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
638 }
639 else {
640 STRNCPY(name, chan->name);
641 }
642
643 /* only copy when:
644 * 1) channel exists - poses are not meant to add random channels to anymore
645 * 2) if selection-masking is on, channel is selected -
646 * only selected bones get pasted on, allowing making both sides symmetrical.
647 */
648 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name);
649 if (pchan == nullptr) {
650 return nullptr;
651 }
652 if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) {
653 return nullptr;
654 }
655
656 /* only loc rot size
657 * - only copies transform info for the pose
658 */
659 copy_v3_v3(pchan->loc, chan->loc);
660 copy_v3_v3(pchan->size, chan->size);
661 pchan->flag = chan->flag;
662
663 /* check if rotation modes are compatible (i.e. do they need any conversions) */
664 if (pchan->rotmode == chan->rotmode) {
665 /* copy the type of rotation in use */
666 if (pchan->rotmode > 0) {
667 copy_v3_v3(pchan->eul, chan->eul);
668 }
669 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
670 copy_v3_v3(pchan->rotAxis, chan->rotAxis);
671 pchan->rotAngle = chan->rotAngle;
672 }
673 else {
674 copy_qt_qt(pchan->quat, chan->quat);
675 }
676 }
677 else if (pchan->rotmode > 0) {
678 /* quat/axis-angle to euler */
679 if (chan->rotmode == ROT_MODE_AXISANGLE) {
680 axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
681 }
682 else {
683 quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
684 }
685 }
686 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
687 /* quat/euler to axis angle */
688 if (chan->rotmode > 0) {
689 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
690 }
691 else {
692 quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
693 }
694 }
695 else {
696 /* euler/axis-angle to quat */
697 if (chan->rotmode > 0) {
698 eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
699 }
700 else {
701 axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
702 }
703 }
704
705 /* B-Bone posing options should also be included... */
706 pchan->curve_in_x = chan->curve_in_x;
707 pchan->curve_in_z = chan->curve_in_z;
708 pchan->curve_out_x = chan->curve_out_x;
709 pchan->curve_out_z = chan->curve_out_z;
710
711 pchan->roll1 = chan->roll1;
712 pchan->roll2 = chan->roll2;
713 pchan->ease1 = chan->ease1;
714 pchan->ease2 = chan->ease2;
715
716 copy_v3_v3(pchan->scale_in, chan->scale_in);
717 copy_v3_v3(pchan->scale_out, chan->scale_out);
718
719 /* paste flipped pose? */
720 if (flip) {
721 pchan->loc[0] *= -1;
722
723 pchan->curve_in_x *= -1;
724 pchan->curve_out_x *= -1;
725 pchan->roll1 *= -1; /* XXX? */
726 pchan->roll2 *= -1; /* XXX? */
727
728 /* has to be done as eulers... */
729 if (pchan->rotmode > 0) {
730 pchan->eul[1] *= -1;
731 pchan->eul[2] *= -1;
732 }
733 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
734 float eul[3];
735
737 eul[1] *= -1;
738 eul[2] *= -1;
740 }
741 else {
742 float eul[3];
743
744 normalize_qt(pchan->quat);
745 quat_to_eul(eul, pchan->quat);
746 eul[1] *= -1;
747 eul[2] *= -1;
748 eul_to_quat(pchan->quat, eul);
749 }
750 }
751
752 /* ID properties */
753 if (chan->prop) {
754 if (pchan->prop) {
755 /* if we have existing properties on a bone, just copy over the values of
756 * matching properties (i.e. ones which will have some impact) on to the
757 * target instead of just blinding replacing all [
758 */
759 IDP_SyncGroupValues(pchan->prop, chan->prop);
760 }
761 else {
762 /* no existing properties, so assume that we want copies too? */
763 pchan->prop = IDP_CopyProperty(chan->prop);
764 }
765 }
766
767 return pchan;
768}
769
772/* -------------------------------------------------------------------- */
777{
778 using namespace blender::bke::blendfile;
779
780 Main *bmain = CTX_data_main(C);
782
783 /* Sanity checking. */
784 if (ELEM(nullptr, ob, ob->pose)) {
785 BKE_report(op->reports, RPT_ERROR, "No pose to copy");
786 return OPERATOR_CANCELLED;
787 }
788 /* Sets chan->flag to POSE_KEY if bone selected. */
789 set_pose_keys(ob);
790
792 copybuffer.id_add(
793 &ob->id,
794 PartialWriteContext::IDAddOptions{PartialWriteContext::IDAddOperations(
795 PartialWriteContext::IDAddOperations::MAKE_LOCAL |
796 PartialWriteContext::IDAddOperations::SET_FAKE_USER |
797 PartialWriteContext::IDAddOperations::SET_CLIPBOARD_MARK)},
798 [ob](LibraryIDLinkCallbackData *cb_data,
800 /* Only include `ob->data` (i.e. the Armature) dependency. */
801 if (*(cb_data->id_pointer) == ob->data) {
802 return PartialWriteContext::IDAddOperations(
803 PartialWriteContext::IDAddOperations::MAKE_LOCAL |
804 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES);
805 }
806 return PartialWriteContext::IDAddOperations::CLEAR_DEPENDENCIES;
807 });
808
809 char filepath[FILE_MAX];
810 pose_copybuffer_filepath_get(filepath, sizeof(filepath));
811 copybuffer.write(filepath, *op->reports);
812
813 /* We are all done! */
814 BKE_report(op->reports, RPT_INFO, "Copied pose to internal clipboard");
815 return OPERATOR_FINISHED;
816}
817
819{
820 /* identifiers */
821 ot->name = "Copy Pose";
822 ot->idname = "POSE_OT_copy";
823 ot->description = "Copy the current pose of the selected bones to the internal clipboard";
824
825 /* api callbacks */
828
829 /* flag */
831}
832
835/* -------------------------------------------------------------------- */
840{
842 Scene *scene = CTX_data_scene(C);
843 const bool flip = RNA_boolean_get(op->ptr, "flipped");
844 bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
845
846 /* Get KeyingSet to use. */
848
849 /* Sanity checks. */
850 if (ELEM(nullptr, ob, ob->pose)) {
851 return OPERATOR_CANCELLED;
852 }
853
854 /* Read copy buffer .blend file. */
855 char filepath[FILE_MAX];
856 Main *temp_bmain = BKE_main_new();
858
859 pose_copybuffer_filepath_get(filepath, sizeof(filepath));
860 if (!BKE_copybuffer_read(temp_bmain, filepath, op->reports, FILTER_ID_OB)) {
861 BKE_report(op->reports, RPT_ERROR, "Internal clipboard is empty");
862 BKE_main_free(temp_bmain);
863 return OPERATOR_CANCELLED;
864 }
865 /* Make sure data from this file is usable for pose paste. */
866 if (!BLI_listbase_is_single(&temp_bmain->objects)) {
867 BKE_report(op->reports, RPT_ERROR, "Internal clipboard is not from pose mode");
868 BKE_main_free(temp_bmain);
869 return OPERATOR_CANCELLED;
870 }
871
872 Object *object_from = static_cast<Object *>(temp_bmain->objects.first);
873 bPose *pose_from = object_from->pose;
874 if (pose_from == nullptr) {
875 BKE_report(op->reports, RPT_ERROR, "Internal clipboard has no pose");
876 BKE_main_free(temp_bmain);
877 return OPERATOR_CANCELLED;
878 }
879
880 /* If selOnly option is enabled, if user hasn't selected any bones,
881 * just go back to default behavior to be more in line with other
882 * pose tools.
883 */
884 if (selOnly) {
885 if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
886 selOnly = false;
887 }
888 }
889
890 /* Safely merge all of the channels in the buffer pose into any
891 * existing pose.
892 */
893 LISTBASE_FOREACH (bPoseChannel *, chan, &pose_from->chanbase) {
894 if (chan->flag & POSE_KEY) {
895 /* Try to perform paste on this bone. */
896 bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
897 if (pchan != nullptr) {
898 /* Keyframing tagging for successful paste, */
899 blender::animrig::autokeyframe_pchan(C, scene, ob, pchan, ks);
900 }
901 }
902 }
903 BKE_main_free(temp_bmain);
904
905 /* Update event for pose and deformation children. */
907
908 /* Recalculate paths if any of the bones have paths... */
911 }
912
913 /* Notifiers for updates, */
915
916 return OPERATOR_FINISHED;
917}
918
920{
921 PropertyRNA *prop;
922
923 /* identifiers */
924 ot->name = "Paste Pose";
925 ot->idname = "POSE_OT_paste";
926 ot->description = "Paste the stored pose on to the current pose";
927
928 /* api callbacks */
931
932 /* flag */
934
935 /* properties */
936 prop = RNA_def_boolean(ot->srna,
937 "flipped",
938 false,
939 "Flipped on X-Axis",
940 "Paste the stored pose flipped on to current pose");
942
944 "selected_mask",
945 false,
946 "On Selected Only",
947 "Only paste the stored pose on to selected bones in the current pose");
948}
949
952/* -------------------------------------------------------------------- */
956/* clear scale of pose-channel */
958{
959 if ((pchan->protectflag & OB_LOCK_SCALEX) == 0) {
960 pchan->size[0] = 1.0f;
961 }
962 if ((pchan->protectflag & OB_LOCK_SCALEY) == 0) {
963 pchan->size[1] = 1.0f;
964 }
965 if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0) {
966 pchan->size[2] = 1.0f;
967 }
968
969 pchan->ease1 = 0.0f;
970 pchan->ease2 = 0.0f;
971
972 copy_v3_fl(pchan->scale_in, 1.0f);
973 copy_v3_fl(pchan->scale_out, 1.0f);
974}
975/* Clear the scale. When X-mirror is enabled,
976 * also clear the scale of the mirrored pose channel. */
977static void pchan_clear_scale_with_mirrored(const bPose *pose, bPoseChannel *pchan)
978{
979 if (pose->flag & POSE_MIRROR_EDIT) {
980 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
981 if (pchan_mirror != nullptr) {
982 pchan_clear_scale(pchan_mirror);
983 }
984 }
985 pchan_clear_scale(pchan);
986}
987
988/* clear location of pose-channel */
989static void pchan_clear_loc(bPoseChannel *pchan)
990{
991 if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
992 pchan->loc[0] = 0.0f;
993 }
994 if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
995 pchan->loc[1] = 0.0f;
996 }
997 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
998 pchan->loc[2] = 0.0f;
999 }
1000}
1001/* Clear the Location. When X-mirror is enabled,
1002 * also clear the location of the mirrored pose channel. */
1003static void pchan_clear_loc_with_mirrored(const bPose *pose, bPoseChannel *pchan)
1004{
1005 if (pose->flag & POSE_MIRROR_EDIT) {
1006 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
1007 if (pchan_mirror != nullptr) {
1008 pchan_clear_loc(pchan_mirror);
1009 }
1010 }
1011 pchan_clear_loc(pchan);
1012}
1013
1014/* clear rotation of pose-channel */
1016{
1018 /* check if convert to eulers for locking... */
1019 if (pchan->protectflag & OB_LOCK_ROT4D) {
1020 /* perform clamping on a component by component basis */
1021 if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1022 if ((pchan->protectflag & OB_LOCK_ROTW) == 0) {
1023 pchan->rotAngle = 0.0f;
1024 }
1025 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1026 pchan->rotAxis[0] = 0.0f;
1027 }
1028 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1029 pchan->rotAxis[1] = 0.0f;
1030 }
1031 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1032 pchan->rotAxis[2] = 0.0f;
1033 }
1034
1035 /* check validity of axis - axis should never be 0,0,0
1036 * (if so, then we make it rotate about y). */
1037 if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) &&
1038 IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
1039 {
1040 pchan->rotAxis[1] = 1.0f;
1041 }
1042 }
1043 else if (pchan->rotmode == ROT_MODE_QUAT) {
1044 if ((pchan->protectflag & OB_LOCK_ROTW) == 0) {
1045 pchan->quat[0] = 1.0f;
1046 }
1047 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1048 pchan->quat[1] = 0.0f;
1049 }
1050 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1051 pchan->quat[2] = 0.0f;
1052 }
1053 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1054 pchan->quat[3] = 0.0f;
1055 }
1056 }
1057 else {
1058 /* the flag may have been set for the other modes, so just ignore the extra flag... */
1059 if ((pchan->protectflag & OB_LOCK_ROTX) == 0) {
1060 pchan->eul[0] = 0.0f;
1061 }
1062 if ((pchan->protectflag & OB_LOCK_ROTY) == 0) {
1063 pchan->eul[1] = 0.0f;
1064 }
1065 if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) {
1066 pchan->eul[2] = 0.0f;
1067 }
1068 }
1069 }
1070 else {
1071 /* perform clamping using euler form (3-components) */
1072 float eul[3], oldeul[3], quat1[4] = {0};
1073 float qlen = 0.0f;
1074
1075 if (pchan->rotmode == ROT_MODE_QUAT) {
1076 qlen = normalize_qt_qt(quat1, pchan->quat);
1077 quat_to_eul(oldeul, quat1);
1078 }
1079 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1080 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
1081 }
1082 else {
1083 copy_v3_v3(oldeul, pchan->eul);
1084 }
1085
1086 eul[0] = eul[1] = eul[2] = 0.0f;
1087
1088 if (pchan->protectflag & OB_LOCK_ROTX) {
1089 eul[0] = oldeul[0];
1090 }
1091 if (pchan->protectflag & OB_LOCK_ROTY) {
1092 eul[1] = oldeul[1];
1093 }
1094 if (pchan->protectflag & OB_LOCK_ROTZ) {
1095 eul[2] = oldeul[2];
1096 }
1097
1098 if (pchan->rotmode == ROT_MODE_QUAT) {
1099 eul_to_quat(pchan->quat, eul);
1100
1101 /* restore original quat size */
1102 mul_qt_fl(pchan->quat, qlen);
1103
1104 /* quaternions flip w sign to accumulate rotations correctly */
1105 if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) ||
1106 (quat1[0] > 0.0f && pchan->quat[0] < 0.0f))
1107 {
1108 mul_qt_fl(pchan->quat, -1.0f);
1109 }
1110 }
1111 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1113 }
1114 else {
1115 copy_v3_v3(pchan->eul, eul);
1116 }
1117 }
1118 } /* Duplicated in source/blender/editors/object/object_transform.cc */
1119 else {
1120 if (pchan->rotmode == ROT_MODE_QUAT) {
1121 unit_qt(pchan->quat);
1122 }
1123 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
1124 /* by default, make rotation of 0 radians around y-axis (roll) */
1125 unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
1126 }
1127 else {
1128 zero_v3(pchan->eul);
1129 }
1130 }
1131
1132 /* Clear also Bendy Bone stuff - Roll is obvious,
1133 * but Curve X/Y stuff is also kind of rotational in nature... */
1134 pchan->roll1 = 0.0f;
1135 pchan->roll2 = 0.0f;
1136
1137 pchan->curve_in_x = 0.0f;
1138 pchan->curve_in_z = 0.0f;
1139 pchan->curve_out_x = 0.0f;
1140 pchan->curve_out_z = 0.0f;
1141}
1142/* Clear the rotation. When X-mirror is enabled,
1143 * also clear the rotation of the mirrored pose channel. */
1144static void pchan_clear_rot_with_mirrored(const bPose *pose, bPoseChannel *pchan)
1145{
1146 if (pose->flag & POSE_MIRROR_EDIT) {
1147 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(pose, pchan->name);
1148 if (pchan_mirror != nullptr) {
1149 pchan_clear_rot(pchan_mirror);
1150 }
1151 }
1152 pchan_clear_rot(pchan);
1153}
1154
1155/* clear loc/rot/scale of pose-channel */
1156static void pchan_clear_transforms(const bPose *pose, bPoseChannel *pchan)
1157{
1158 pchan_clear_loc_with_mirrored(pose, pchan);
1159 pchan_clear_rot_with_mirrored(pose, pchan);
1161}
1162
1163/* --------------- */
1164
1165/* generic exec for clear-pose operators */
1167 wmOperator *op,
1168 void (*clear_func)(const bPose *, bPoseChannel *),
1169 const char default_ksName[])
1170{
1172 Scene *scene = CTX_data_scene(C);
1173 bool changed_multi = false;
1174
1175 /* sanity checks */
1176 if (ELEM(nullptr, clear_func, default_ksName)) {
1177 BKE_report(op->reports,
1178 RPT_ERROR,
1179 "Programming error: missing clear transform function or keying set name");
1180 return OPERATOR_CANCELLED;
1181 }
1182
1183 /* only clear relevant transforms for selected bones */
1184 ViewLayer *view_layer = CTX_data_view_layer(C);
1185 View3D *v3d = CTX_wm_view3d(C);
1186 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
1187 /* XXX: UGLY HACK (for auto-key + clear transforms). */
1188 Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
1190 bool changed = false;
1191
1193 /* run provided clearing function */
1194 clear_func(ob_iter->pose, pchan);
1195 changed = true;
1196
1197 /* do auto-keyframing as appropriate */
1198 if (blender::animrig::autokeyframe_cfra_can_key(scene, &ob_iter->id)) {
1199 /* tag for autokeying later */
1200 ANIM_relative_keyingset_add_source(sources, &ob_iter->id, &RNA_PoseBone, pchan);
1201
1202#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */
1203 bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
1204 clear_func(ob_iter->pose, pchan_eval);
1205#endif
1206 }
1207 }
1209
1210 if (changed) {
1211 changed_multi = true;
1212
1213 /* perform autokeying on the bones if needed */
1214 if (!sources.is_empty()) {
1215 /* get KeyingSet to use */
1216 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
1217
1218 /* insert keyframes */
1220 C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra));
1221
1222 /* now recalculate paths */
1223 if (ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
1225 }
1226 }
1227
1229
1230 /* NOTE: notifier might evolve. */
1232 }
1233 }
1235
1236 return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1237}
1238
1241/* -------------------------------------------------------------------- */
1250
1252{
1253 /* identifiers */
1254 ot->name = "Clear Pose Scale";
1255 ot->idname = "POSE_OT_scale_clear";
1256 ot->description = "Reset scaling of selected bones to their default values";
1257
1258 /* api callbacks */
1261
1262 /* flags */
1264}
1265
1268/* -------------------------------------------------------------------- */
1277
1279{
1280 /* identifiers */
1281 ot->name = "Clear Pose Rotation";
1282 ot->idname = "POSE_OT_rot_clear";
1283 ot->description = "Reset rotations of selected bones to their default values";
1284
1285 /* api callbacks */
1288
1289 /* flags */
1291}
1292
1295/* -------------------------------------------------------------------- */
1304
1306{
1307 /* identifiers */
1308 ot->name = "Clear Pose Location";
1309 ot->idname = "POSE_OT_loc_clear";
1310 ot->description = "Reset locations of selected bones to their default values";
1311
1312 /* api callbacks */
1315
1316 /* flags */
1318}
1319
1322/* -------------------------------------------------------------------- */
1331
1333{
1334 /* identifiers */
1335 ot->name = "Clear Pose Transforms";
1336 ot->idname = "POSE_OT_transforms_clear";
1337 ot->description =
1338 "Reset location, rotation, and scaling of selected bones to their default values";
1339
1340 /* api callbacks */
1343
1344 /* flags */
1346}
1347
1350/* -------------------------------------------------------------------- */
1355{
1356 ViewLayer *view_layer = CTX_data_view_layer(C);
1357 View3D *v3d = CTX_wm_view3d(C);
1358 Scene *scene = CTX_data_scene(C);
1359 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
1361 depsgraph, float(scene->r.cfra));
1362 const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
1363
1364 FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
1365 if ((ob->adt) && (ob->adt->action)) {
1366 /* XXX: this is just like this to avoid contaminating anything else;
1367 * just pose values should change, so this should be fine
1368 */
1369 bPose *dummyPose = nullptr;
1370 Object workob{};
1371
1372 /* execute animation step for current frame using a dummy copy of the pose */
1373 BKE_pose_copy_data(&dummyPose, ob->pose, false);
1374
1375 STRNCPY(workob.id.name, "OB<ClearTfmWorkOb>");
1376 workob.type = OB_ARMATURE;
1377 workob.data = ob->data;
1378 workob.adt = ob->adt;
1379 workob.pose = dummyPose;
1380
1382 &workob.id, workob.adt, &anim_eval_context, ADT_RECALC_ANIM, false);
1383
1384 /* Copy back values, but on selected bones only. */
1385 LISTBASE_FOREACH (bPoseChannel *, pchan, &dummyPose->chanbase) {
1386 pose_bone_do_paste(ob, pchan, only_select, false);
1387 }
1388
1389 /* free temp data - free manually as was copied without constraints */
1390 LISTBASE_FOREACH (bPoseChannel *, pchan, &dummyPose->chanbase) {
1391 if (pchan->prop) {
1392 IDP_FreeProperty(pchan->prop);
1393 }
1394 }
1395
1396 /* was copied without constraints */
1397 BLI_freelistN(&dummyPose->chanbase);
1398 MEM_freeN(dummyPose);
1399 }
1400 else {
1401 /* No animation, so just reset to the rest pose. */
1402 BKE_pose_rest(ob->pose, only_select);
1403 }
1404
1405 /* notifiers and updates */
1408 }
1410
1411 return OPERATOR_FINISHED;
1412}
1413
1415{
1416 /* identifiers */
1417 ot->name = "Clear User Transforms";
1418 ot->idname = "POSE_OT_user_transforms_clear";
1419 ot->description = "Reset pose bone transforms to keyframed state";
1420
1421 /* callbacks */
1424
1425 /* flags */
1427
1428 /* properties */
1429 RNA_def_boolean(ot->srna, "only_selected", true, "Only Selected", "Only visible/selected bones");
1430}
1431
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bone_in_visible_collection(const bArmature *armature, const Bone *bone)
Functions to insert, delete or modify keyframes.
Functionality to interact with keying sets.
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:734
@ 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:1211
bArmature * BKE_armature_from_object(Object *ob)
Definition armature.cc:522
void BKE_bone_parent_transform_clear(BoneParentTransform *bpt)
Definition armature.cc:2213
void BKE_bone_parent_transform_combine(const BoneParentTransform *in1, const BoneParentTransform *in2, BoneParentTransform *result)
Definition armature.cc:2227
void BKE_bone_parent_transform_invert(BoneParentTransform *bpt)
Definition armature.cc:2220
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
Definition armature.cc:2467
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
Definition armature.cc:2358
void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, const float inmat[4][4], float outmat[4][4])
Definition armature.cc:2249
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_END
#define PBONE_VISIBLE(arm, bone)
void BKE_bone_parent_transform_apply(const BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4])
Definition armature.cc:2236
void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3])
Definition armature.cc:2611
void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob)
Definition armature.cc:2941
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)
Definition armature.cc:2068
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan)
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
Definition armature.cc:2025
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:1227
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:861
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) ATTR_NONNULL()
Definition idprop.cc:578
#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(void)
Definition main.cc:45
void BKE_main_free(Main *bmain)
Definition main.cc:175
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
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)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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 unit_m4(float m[4][4])
Definition rct.c:1127
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 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(...)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
#define FILTER_ID_OB
Definition DNA_ID.h:1181
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ MOTIONPATH_BAKE_HAS_PATHS
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ POSE_KEY
@ POSE_MIRROR_EDIT
#define MAXBONENAME
@ BONE_SELECTED
@ BONE_CONNECTED
@ CONSTRAINT_TYPE_STRETCHTO
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ PARBONE
@ 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
@ OB_ARMATURE
@ POSE_PATH_CALC_RANGE_FULL
#define ANIM_KS_LOC_ROT_SCALE_ID
#define ANIM_KS_LOCATION_ID
#define ANIM_KS_WHOLE_CHARACTER_ID
#define ANIM_KS_SCALING_ID
#define ANIM_KS_ROTATION_ID
bool ED_operator_posemode(bContext *C)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define UI_ITEM_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_POSE
Definition WM_types.hh:425
#define ND_TRANSFORM
Definition WM_types.hh:423
#define NC_OBJECT
Definition WM_types.hh:346
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)
bool is_empty() const
ID * id_add(const ID *id, IDAddOptions options, blender::FunctionRef< IDAddOperations(LibraryIDLinkCallbackData *cb_data, IDAddOptions options)> dependencies_filter_cb=nullptr)
const Depsgraph * depsgraph
draw_view in_light_buf[] float
void ANIM_relative_keyingset_add_source(blender::Vector< PointerRNA > &sources, ID *id, StructRNA *srna, void *data)
KeyingSet * ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
int ANIM_apply_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset, const blender::animrig::ModifyKeyMode mode, const float cfra)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
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)
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)
void POSE_OT_paste(wmOperatorType *ot)
static int pose_copy_exec(bContext *C, wmOperator *op)
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 void applyarmature_process_selected_recursive(bArmature *arm, bPose *pose, bPose *pose_eval, Bone *bone, blender::Span< PointerRNA > selected, ApplyArmature_ParentState *pstate)
static int pose_paste_exec(bContext *C, wmOperator *op)
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 int pose_visual_transform_apply_exec(bContext *C, wmOperator *)
static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
static void applyarmature_reset_bone_constraint(const bConstraint *constraint)
static void pchan_clear_loc_with_mirrored(const bPose *pose, bPoseChannel *pchan)
static int pose_clear_rot_exec(bContext *C, wmOperator *op)
static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
static int 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)
static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
void POSE_OT_copy(wmOperatorType *ot)
void POSE_OT_rot_clear(wmOperatorType *ot)
static int pose_clear_scale_exec(bContext *C, wmOperator *op)
static void applyarmature_adjust_edit_position(bArmature *arm, bPoseChannel *pchan, const float delta_mat[4][4], float r_new_arm_mat[4][4])
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 set_pose_keys(Object *ob)
static void pchan_clear_loc(bPoseChannel *pchan)
void POSE_OT_scale_clear(wmOperatorType *ot)
void POSE_OT_user_transforms_clear(wmOperatorType *ot)
static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
static void pchan_clear_rot_with_mirrored(const bPose *pose, bPoseChannel *pchan)
static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op, void(*clear_func)(const bPose *, bPoseChannel *), const char default_ksName[])
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(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]
void * first
char filepath[1024]
Definition BKE_main.hh:136
ListBase objects
Definition BKE_main.hh:212
struct bPose * pose
struct AnimData * adt
ListBase * edbo
IDProperty * prop
struct Bone * bone
struct bPoseChannel * parent
float pose_mat[4][4]
ListBase chanbase
bAnimVizSettings avs
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(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125