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