/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. * * SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bke */ #include #include "BLI_bounds_types.hh" #include "BLI_function_ref.hh" #include "BLI_math_matrix_types.hh" #include "BLI_math_vector_types.hh" #include "BLI_mutex.hh" #include "BLI_set.hh" #include "DNA_armature_types.h" #include "DNA_listBase.h" #include "BKE_pose.hh" namespace blender { struct bDeformGroup; struct BMEditMesh; struct Bone; struct Depsgraph; struct IDProperty; struct Main; struct Mesh; struct Object; struct PoseTree; struct Scene; struct bArmature; struct bConstraint; struct bPose; struct bPoseChannel; struct MDeformVert; enum eRotationModes : short; struct EditBone { EditBone *next = nullptr, *prev = nullptr; /** User-Defined Properties on this Bone */ IDProperty *prop = nullptr; /** System-Defined Properties storage. */ IDProperty *system_properties = nullptr; /** * Edit-bones have a one-way link (i.e. children refer to parents). * This is converted to a two-way link for normal bones when leaving edit-mode. */ EditBone *parent = nullptr; char name[/*MAXBONENAME*/ 64] = ""; /** * Roll along axis. We'll ultimately use the axis/angle method * for determining the transformation matrix of the bone. The axis * is tail-head while roll provides the angle. Refer to Graphics * Gems 1 p. 466 (section IX.6) if it's not already in here somewhere. */ float roll = 0.0f; /** Orientation and length is implicit during editing */ float head[3] = {}; float tail[3] = {}; /** * All joints are considered to have zero rotation with respect to * their parents. Therefore any rotations specified during the * animation are automatically relative to the bones' rest positions. */ eBone_Flag flag = {}; int layer = 0; int drawtype = 0; /* eArmature_Drawtype */ eBone_InheritScaleMode inherit_scale_mode = BONE_INHERIT_SCALE_FULL; /* Envelope distance & weight */ float dist = 0, weight = 0; /** put them in order! transform uses this as scale */ float xwidth = 0, length = 0, zwidth = 0; float rad_head = 0, rad_tail = 0; /* Bendy-Bone parameters */ short segments = 0; float roll1 = 0, roll2 = 0; float curve_in_x = 0, curve_in_z = 0; float curve_out_x = 0, curve_out_z = 0; float ease1 = 0, ease2 = 0; float scale_in[3] = {}, scale_out[3] = {}; /** for envelope scaling */ float oldlength = 0; /** Mapping of vertices to segments. */ eBone_BBoneMappingMode bbone_mapping_mode = BBONE_MAPPING_STRAIGHT; /** Type of next/prev bone handles */ eBone_BBoneHandleType bbone_prev_type = BBONE_HANDLE_AUTO; eBone_BBoneHandleType bbone_next_type = BBONE_HANDLE_AUTO; /** B-Bone flags. */ eBone_BBoneFlag bbone_flag = {}; eBone_BBoneHandleFlag bbone_prev_flag = {}; eBone_BBoneHandleFlag bbone_next_flag = {}; /** Next/prev bones to use as handle references when calculating bbones (optional) */ EditBone *bbone_prev = nullptr; EditBone *bbone_next = nullptr; /* Used for display */ /** in Armature space, rest pos matrix */ float disp_mat[4][4] = {}; /** in Armature space, rest pos matrix */ float disp_tail_mat[4][4] = {}; /** in Armature space, rest pos matrix. */ float disp_bbone_mat[/*MAX_BBONE_SUBDIV*/ 32][4][4] = {}; /** connected child temporary during drawing */ EditBone *bbone_child = nullptr; BoneColor color; /* MUST be named the same as in bPoseChannel and Bone structs. */ ListBaseT bone_collections = {}; /* Used to store temporary data */ union { EditBone *ebone = nullptr; Bone *bone; void *p; int i; } temp; }; struct PoseTarget { PoseTarget *next, *prev; bConstraint *con; /* the constraint of this target */ int tip; /* index of tip pchan in PoseTree */ }; struct PoseTree { PoseTree *next, *prev; int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */ int totchannel; /* number of pose channels */ ListBaseT targets; /* list of targets of the tree */ bPoseChannel **pchan; /* array of pose channels */ int *parent; /* and their parents */ float (*basis_change)[3][3]; /* basis change result from solver */ int iterations; /* iterations from the constraint */ int stretch; /* disable stretching */ }; /* Core armature functionality. */ bArmature *BKE_armature_add(Main *bmain, const char *name); bArmature *BKE_armature_from_object(Object *ob); int BKE_armature_bonelist_count(const ListBaseT *lb); void BKE_armature_bonelist_free(ListBaseT *lb, bool do_id_user); void BKE_armature_editbonelist_free(ListBaseT *lb, bool do_id_user); void BKE_armature_copy_bone_transforms(bArmature *armature_dst, const bArmature *armature_src); void BKE_armature_transform(bArmature *arm, const float mat[4][4], bool do_props); /** * Return the posed Armature bounding box in object-local coordinate space. */ std::optional> BKE_armature_min_max(const Object *ob); using ForeachBoneFn = FunctionRef; /** * Visit each bone in the armature, in depth-first order. */ void BKE_armature_foreach_bone(const bArmature &armature, ForeachBoneFn callback); /** * Calculate the axis-aligned bounds of `pchan` in object-space, * taking into account custom transform when set. * * `r_min` and `r_max` are expanded to fit `pchan` so the caller must initialize them * (typically using #INIT_MINMAX). * * \note The bounds are calculated based on the head & tail of the bone * or the custom object's bounds (if the bone uses a custom object). * Visual elements such as the envelopes radius & bendy-bone spline segments are *not* included, * making this not so useful for viewport culling. * * \param use_empty_drawtype: When enabled, the draw type of empty custom-objects is taken into * account when calculating the bounds. */ void BKE_pchan_minmax(const Object *ob, bke::PChanBoneConst pchanbone, bool use_empty_drawtype, float3 &r_min, float3 &r_max); /** * Calculate the axis aligned bounds of the pose of `ob` in object-space. * * This only considers visible bones. When they are either directly (via a flag on the bone) or * indirectly (via bone collections) hidden, they are not part of the bounds calculation. When a * bone has a custom bone shape, that is included in the bounding box. * * \note This uses #BKE_pchan_minmax, see its documentation for details on bounds calculation. * * \param use_select: When true, only consider selected bones. When false, selection state is * ignored and all bones are included in the bounds. */ std::optional> BKE_pose_minmax(const Object *ob, bool use_select); /** * Finds the best possible extension to the name on a particular axis. * (For renaming, check for unique names afterwards) * \param strip_number: removes number extensions (TODO: not used). * \param axis: The axis to name on. * \param head: The head coordinate of the bone on the specified axis. * \param tail: The tail coordinate of the bone on the specified axis. */ bool bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail); /** * Find the bone with the given name. * * When doing multiple subsequent calls to this function, consider calling * #BKE_armature_bone_hash_make first to hash the bone names and speed up * queries. */ Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name); void BKE_armature_bone_hash_make(bArmature *arm); void BKE_armature_bone_hash_free(bArmature *arm); bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag); /** * Bone influence factor from envelope distance. */ float distfactor_to_bone(const float3 &position, const float3 &head, const float3 &tail, float radius_head, float radius_tail, float falloff_distance); /** * Updates vectors and matrices on rest-position level, only needed * after editing armature itself, now only on reading file. */ void BKE_armature_where_is(bArmature *arm); /** * Recursive part, calculates rest-position of entire tree of children. * \note Used when exiting edit-mode too. */ void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, bool use_recursion); /** * Clear pointers of object's pose * (needed in remap case, since we cannot always wait for a complete pose rebuild). */ void BKE_pose_clear_pointers(bPose *pose); /** * Update the links for the B-Bone handles from Bone data. */ void BKE_pchan_rebuild_bbone_handles(bPose *pose, bke::PChanBone pchanbone); void BKE_pose_channels_clear_with_null_bone(Object *armature_ob, bool do_id_user); /** * Only after leave edit-mode, duplicating, validating older files, library syncing. * * \note pose->flag is set for it. * * \param bmain: May be NULL, only used to tag depsgraph as being dirty. */ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, bool do_id_user); /** * Ensures object's pose is rebuilt if needed. * * \param bmain: May be NULL, only used to tag depsgraph as being dirty. */ void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user); /** * Ensure the object's pose bone indices are up to date. * * This is only necessary when calling `pchan->bone_get(armature)`, as that cannot verify the * up-to-dateness of the pose bone indices. * * When calling `pchan->bone_get(object)` the check is performed automatically. However, calling * that in a hot loop will cost some performance; passing the armature is preferred in that case. * * This takes a const Object, because it does not modify anything except its pose channels' runtime * field `bone_index`. There is no conceptual change to the object, it's just the bone lookup info * that's being refreshed. Ideally the field would be marked `mutable`, but currently the * bPoseChannel_runtime struct is part of DNA, which doesn't support that keyword. */ void BKE_pose_ensure_bone_indices(const Object &pose_object); /** * \note This is the only function adding poses. * \note This only reads anim data from channels, and writes to channels. */ void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob); /** * The main armature solver, does all constraints excluding IK. * * \param pchan: pose-channel - validated, as having bone and parent pointer. * \param do_extra: when zero skips loc/size/rot, constraints and strip modifiers. */ void BKE_pose_where_is_bone(Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, bool do_extra); /** * Calculate tail of pose-channel. */ void BKE_pose_where_is_bone_tail(bke::PChanBone pchanbone); void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3]); /** * Calculates the rest matrix of a bone based on its vector and a roll around that vector. */ void vec_roll_to_mat3_normalized(const float nor[3], float roll, float r_mat[3][3]); /** * Computes vector and roll based on a rotation. * "mat" must contain only a rotation, and no scaling. */ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll); /** * Computes roll around the vector that best approximates the matrix. * If `vec` is the Y vector from purely rotational `mat`, result should be exact. */ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll); /* Common Conversions Between Coordinate Spaces */ /** * Convert World-Space Matrix to Pose-Space Matrix. */ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float outmat[4][4]); /** * Convert World-Space Location to Pose-Space Location * \note this cannot be used to convert to pose-space location of the supplied * pose-channel into its local space (i.e. *visual*-keyframing). */ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outloc[3]); /** * Convert Pose-Space Matrix to Bone-Space Matrix. * \note this cannot be used to convert to pose-space transforms of the supplied * pose-channel into its local space (i.e. *visual*-keyframing). */ void BKE_armature_mat_pose_to_bone(bke::PChanBoneConst pchanbone, const float inmat[4][4], float outmat[4][4]); /** * Convert Pose-Space Location to Bone-Space Location * \note this cannot be used to convert to pose-space location of the supplied * pose-channel into its local space (i.e. *visual*-keyframing). */ void BKE_armature_loc_pose_to_bone(bke::PChanBoneConst pchanbone, const float inloc[3], float outloc[3]); /** * Convert Bone-Space Matrix to Pose-Space Matrix. */ void BKE_armature_mat_bone_to_pose(bke::PChanBoneConst pchanbone, const float inmat[4][4], float outmat[4][4]); /** * Remove rest-position effects from pose-transform for obtaining * 'visual' transformation of pose-channel. * (used by the Visual-Keyframing stuff). */ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]); void BKE_armature_mat_pose_to_bone_ex(Depsgraph *depsgraph, Object *ob, const bPoseChannel *pchan, const float inmat[4][4], float outmat[4][4]); /** * Same as #BKE_object_mat3_to_rot(). * * \param use_compat: only applies when the `pchan` is in euler rotation mode. It then picks the * closest euler values relative to what the `pchan` already has. */ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_compat); /** * Same as #BKE_object_rot_to_mat3(). */ void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3]); /** * Returns a quaternion representation of the current rotation of the bone. * Euler and Axis Angle will be converted to Quaternion and then returned. */ float4 BKE_pchan_rot_to_quat(const bPoseChannel &pchan); /** * Applies the quaternion rotation to the current rotation of the bone. * Depending on the `pchan.rotmode` this modifies either Euler, Axis Angle or Quaternion values. */ void BKE_pchan_quat_to_rot(bPoseChannel &pchan, const float4 &quat); /** * Apply a 4x4 matrix to the pose bone, * similar to #BKE_object_apply_mat4(). */ void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat); /** * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat). */ void BKE_pchan_to_mat4(bke::PChanBoneConst pchanbone, float r_chanmat[4][4]); /** * Convert the loc/rot/size to mat4 (`pchan.chan_mat`), * used in `constraint.cc` too. */ void BKE_pchan_calc_mat(bke::PChanBone pchanbone); /** * Simple helper, computes the offset bone matrix: * `offs_bone = yoffs(b-1) + root(b) + bonemat(b)`. */ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4]); /* Transformation inherited from the parent bone. These matrices apply the effects of * HINGE/NO_SCALE/NO_LOCAL_LOCATION options over the pchan loc/rot/scale transformations. */ struct BoneParentTransform { float rotscale_mat[4][4]; /* parent effect on rotation & scale pose channels */ float loc_mat[4][4]; /* parent effect on location pose channel */ float post_scale[3]; /* additional scale to apply with post-multiply */ }; /* Matrix-like algebra operations on the transform */ void BKE_bone_parent_transform_clear(BoneParentTransform *bpt); void BKE_bone_parent_transform_invert(BoneParentTransform *bpt); void BKE_bone_parent_transform_combine(const BoneParentTransform *in1, const BoneParentTransform *in2, BoneParentTransform *result); void BKE_bone_parent_transform_apply(const BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4]); /** * Get the current parent transformation for the given pose bone. * * Construct the matrices (rot/scale and loc) * to apply the PoseChannels into the armature (object) space. * I.e. (roughly) the `pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)` in the * `pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)` * ...function. * * This allows to get the transformations of a bone in its object space, * *before* constraints (and IK) get applied (used by pose evaluation code). * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale * in object space (used by interactive transform, and snapping code). * * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix * will differ from the rotation/scale matrix... * * \note This cannot be used to convert to pose-space transforms of the supplied * pose-channel into its local space (i.e. *visual*-key-framing). * (NOTE(@mont29): I don't understand that, so I keep it :p). */ void BKE_bone_parent_transform_calc_from_pchan(bke::PChanBoneConst pchanbone, BoneParentTransform *r_bpt); /** * Compute the parent transform using data decoupled from specific data structures. * * \param bone_flag: #Bone.flag containing settings. * \param offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent). * \param parent_arm_mat: arm_mat of parent, or NULL. * \param parent_pose_mat: pose_mat of parent, or NULL. * \param r_bpt: OUTPUT parent transform. */ 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); /** * Rotation Mode Conversions - Used for Pose-Channels + Objects. * * Called from RNA when rotation mode changes * - the result should be that the rotations given in the provided pointers have had conversions * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed. */ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, eRotationModes oldMode, eRotationModes newMode); /* B-Bone support */ #define MAX_BBONE_SUBDIV 32 struct Mat4 { float mat[4][4]; }; struct BBoneSplineParameters { int segments; float length; /* Non-uniform scale correction. */ bool do_scale; float scale[3]; /* Handle control bone data. */ bool use_prev, prev_bbone; bool use_next, next_bbone; float prev_h[3], next_h[3]; float prev_mat[4][4], next_mat[4][4]; /* Control values. */ float ease1, ease2; float roll1, roll2; float scale_in[3], scale_out[3]; float curve_in_x, curve_in_z, curve_out_x, curve_out_z; }; /** Sets the location of the pose channel, respecting #bPoseChannel::protectflag. */ void BKE_pchan_protected_location_set(bPoseChannel *pchan, const float location[3]); /** Sets the rotation of the pose channel, respecting the #bPoseChannel::protectflag. Depending on * the current rotation mode, this either modifies quaternion, euler or axis angle. */ void BKE_pchan_protected_rotation_set(bPoseChannel *pchan, const float mat[3][3]); /** Sets the location of the pose channel, respecting #bPoseChannel::protectflag. */ void BKE_pchan_protected_scale_set(bPoseChannel *pchan, const float scale[3]); /** Sets the quaternion rotation of the pose channel, respecting #bPoseChannel::protectflag. */ void BKE_pchan_protected_rotation_quaternion_set(bPoseChannel *pchan, const float quat[4]); /** Sets the euler rotation of the pose channel, respecting #bPoseChannel::protectflag. */ void BKE_pchan_protected_rotation_euler_set(bPoseChannel *pchan, const float rotation_euler[3]); /** Sets the axis-angle rotation of the pose channel, respecting #bPoseChannel::protectflag. */ void BKE_pchan_protected_rotation_axisangle_set(bPoseChannel *pchan, const float axis[3], float angle); /** * Get "next" and "prev" bones - these are used for handle calculations. */ void BKE_pchan_bbone_handles_get(bke::PChanBoneConst pchanbone, bPoseChannel **r_prev, bPoseChannel **r_next); /** * Compute B-Bone spline parameters for the given channel. */ void BKE_pchan_bbone_spline_params_get(bke::PChanBoneConst pchanbone, const bArmature &armature, bool rest, BBoneSplineParameters *param); /** * Fills the array with the desired amount of bone->segments elements. * This calculation is done within unit bone space. */ void BKE_pchan_bbone_spline_setup(bke::PChanBone pchanbone, const bArmature &armature, bool rest, bool for_deform, Mat4 *result_array); /** * Computes the bezier handle vectors and rolls coming from custom handles. */ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets); /** * Fills the array with the desired amount of `bone->segments` elements. * This calculation is done within unit bone space. */ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, bool for_deform, Mat4 *result_array); /** * Compute and cache the B-Bone shape in the channel runtime struct. */ void BKE_pchan_bbone_segments_cache_compute(bke::PChanBone pchanbone, const bArmature &armature); /** * Copy cached B-Bone segments from one channel to another. */ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pchan_from); /** * Calculate index and blend factor for the two B-Bone segment nodes * affecting the specified point along the bone. * * \param bone: Pose channel's armature bone. * \param head_tail: head-tail position along the bone (auto-clamped between 0 and 1). * \param r_index: OUTPUT index of the first segment joint affecting the point. * \param r_blend_next: OUTPUT blend factor between the first and the second segment in [0..1] */ void BKE_pchan_bbone_deform_clamp_segment_index(const Bone &bone, float head_tail, int *r_index, float *r_blend_next); /** * Calculate index and blend factor for the two B-Bone segment nodes * affecting the specified point in object (pose) space. * * \param pchanbone: Pose channel. * \param co: Pose space coordinates of the point being deformed. * \param r_index: OUTPUT index of the first segment joint affecting the point. * \param r_blend_next: OUTPUT blend factor between the first and the second segment in [0..1] */ void BKE_pchan_bbone_deform_segment_index(bke::PChanBoneConst pchanbone, const float *co, int *r_index, float *r_blend_next); /* context.selected_pose_bones */ #define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \ for (bPoseChannel *_pchan = (bPoseChannel *)(_ob)->pose->chanbase.first; _pchan; \ _pchan = _pchan->next) \ { \ if (animrig::bone_is_visible(((bArmature *)(_ob)->data), {_pchan, _pchan->bone_get(*_ob)}) && \ ((_pchan)->flag & POSE_SELECTED)) \ { #define FOREACH_PCHAN_SELECTED_IN_OBJECT_END \ } \ } \ ((void)0) /* context.visible_pose_bones */ #define FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN(_ob, _pchan) \ for (bPoseChannel *_pchan = (bPoseChannel *)(_ob)->pose->chanbase.first; _pchan; \ _pchan = _pchan->next) \ { \ if (animrig::bone_is_visible(((bArmature *)(_ob)->data), {_pchan, pchan->bone_get(*_ob)})) { #define FOREACH_PCHAN_VISIBLE_IN_OBJECT_END \ } \ } \ ((void)0) /* Evaluation helpers */ struct bKinematicConstraint; struct bPose; struct bSplineIKConstraint; bPoseChannel *BKE_armature_ik_solver_find_root(bPoseChannel *pchan, bKinematicConstraint *data); bPoseChannel *BKE_armature_splineik_solver_find_root(bPoseChannel *pchan, bSplineIKConstraint *data); void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime); void BKE_splineik_execute_tree( Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime); void BKE_pose_pchan_index_rebuild(bPose *pose); void BKE_pose_eval_init(Depsgraph *depsgraph, Scene *scene, Object *object); void BKE_pose_eval_init_ik(Depsgraph *depsgraph, Scene *scene, Object *object); void BKE_pose_eval_bone(Depsgraph *depsgraph, Scene *scene, Object *object, int pchan_index); void BKE_pose_constraints_evaluate(Depsgraph *depsgraph, Scene *scene, Object *object, int pchan_index); void BKE_pose_bone_done(Depsgraph *depsgraph, Object *object, int pchan_index); void BKE_pose_eval_bbone_segments(Depsgraph *depsgraph, Object *object, int pchan_index); void BKE_pose_iktree_evaluate(Depsgraph *depsgraph, Scene *scene, Object *object, int rootchan_index); void BKE_pose_splineik_evaluate(Depsgraph *depsgraph, Scene *scene, Object *object, int rootchan_index); void BKE_pose_eval_done(Depsgraph *depsgraph, Object *object); void BKE_pose_eval_cleanup(Depsgraph *depsgraph, Scene *scene, Object *object); /* -------------------------------------------------------------------- */ /** \name Deform 3D Coordinates by Armature (`armature_deform.cc`) * \{ */ /* Note that we could have a #BKE_armature_deform_coords that doesn't take object data * currently there are no callers for this though. */ void BKE_armature_deform_coords_with_curves(const Object &ob_arm, const Object &ob_target, const ListBaseT *defbase, MutableSpan vert_coords, std::optional> vert_coords_prev, std::optional> vert_deform_mats, Span dverts, int deformflag, StringRefNull defgrp_name); void BKE_armature_deform_coords_with_mesh(const Object &ob_arm, const Object &ob_target, MutableSpan vert_coords, std::optional> vert_coords_prev, std::optional> vert_deform_mats, int deformflag, StringRefNull defgrp_name, const Mesh *me_target); void BKE_armature_deform_coords_with_editmesh( const Object &ob_arm, const Object &ob_target, MutableSpan vert_coords, std::optional> vert_coords_prev, std::optional> vert_deform_mats, int deformflag, StringRefNull defgrp_name, const BMEditMesh &em_target); /** \} */ namespace bke { struct bArmature_Runtime { /** * Index of the active collection, -1 if there is no collection active. * * For UIList support in the user interface. Assigning here does nothing, use * `ANIM_armature_bonecoll_active_set` to set the active bone collection. */ int active_collection_index = 0; BoneCollection *active_collection = nullptr; /** * Indexable storage for bones. The bone hierarchy is stored depth-first, so a bone is followed * by its children. * * Used by bPoseChan::bone_get() to obtain a bone pointer by index. */ Array bones; uint64_t bones_generation_count = 0; /** * Mutex to protect the `bones` and `bones_generation_count` fields. * * This is used when regenerating the bones array, to ensure only a single thread does this. Read * access to the bones array is not protected. So far this has worked well; it's not guaranteed * that there won't be a race condition, though. */ Mutex bones_mutex; /** Clear the `bones` array, ensuring it is rebuilt on its next use. */ void bones_tag_rebuild(); /** * Return whether the `bones` array has bones (true), or whether it needs rebuilding (false). * * Note that this returns 'invalid' when the Armature has no bones. This is because the bones * array is only used to obtain a bone pointer by index, which means it's only valid to be used * when there actually are bones. */ bool is_bones_array_valid() const; }; struct SelectedBonesResult { bool all_bones_selected = true; bool no_bones_selected = true; }; using SelectedBoneCallback = FunctionRef; SelectedBonesResult BKE_armature_find_selected_bones(const bArmature *armature, SelectedBoneCallback callback); using BoneNameSet = Set; /** * Return a set of names of the selected bones. */ BoneNameSet BKE_armature_find_selected_bone_names(const bArmature *armature); BoneNameSet BKE_pose_channel_find_selected_names(const Object *object); }; // namespace bke } // namespace blender