Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_generics.c
| Show All 25 Lines | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_sys_types.h" /* for intptr_t support */ | #include "BLI_sys_types.h" /* for intptr_t support */ | ||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_armature_types.h" | #include "DNA_armature_types.h" | ||||
| #include "DNA_brush_types.h" | #include "DNA_brush_types.h" | ||||
| #include "DNA_constraint_types.h" | |||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_lattice_types.h" | #include "DNA_lattice_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_sequence_types.h" | #include "DNA_sequence_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| ▲ Show 20 Lines • Show All 737 Lines • ▼ Show 20 Lines | else if (t->options & CTX_MASK) { | ||||
| recalcData_mask_common(t); | recalcData_mask_common(t); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * if pose bone (partial) selected, copy data. | * if pose bone (partial) selected, copy data. | ||||
| * context; posemode armature, with mirror editing enabled. | * context; posemode armature, with mirror editing enabled. | ||||
| * | * | ||||
| * \param pid: Optional, apply relative transform when set. | * \param pid: Optional, apply relative transform when set. | ||||
sybren: The fact that this doesn't happen when Auto IK is enabled should be documented here.
| |||||
| */ | */ | ||||
| static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) | static void pose_transform_mirror_update(TransInfo *t, | ||||
| TransDataContainer *tc, | |||||
| Object *ob, | |||||
| PoseInitData_Mirror *pid) | |||||
| { | { | ||||
| float flip_mtx[4][4]; | float flip_mtx[4][4]; | ||||
| unit_m4(flip_mtx); | unit_m4(flip_mtx); | ||||
| flip_mtx[0][0] = -1; | flip_mtx[0][0] = -1; | ||||
| for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; | TransData *td = tc->data; | ||||
| pchan_orig = pchan_orig->next) { | for (int i = tc->data_len; i--; td++) { | ||||
| bPoseChannel *pchan_orig = td->extra; | |||||
| BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM); | |||||
| /* no layer check, correct mirror is more important */ | /* no layer check, correct mirror is more important */ | ||||
| if (pchan_orig->bone->flag & BONE_TRANSFORM) { | |||||
| bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); | bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); | ||||
| if (pchan) { | if (pchan) { | ||||
Done Inline ActionsChanging this to if (pchan == NULL) continue; will cause another unindent of the code below. IMO it's also much easier to read, as it's immediately clear that nothing will happen when a mirrored pose channel cannot be found. sybren: Changing this to `if (pchan == NULL) continue;` will cause another unindent of the code below. | |||||
| /* also do bbone scaling */ | /* also do bbone scaling */ | ||||
| pchan->bone->xwidth = pchan_orig->bone->xwidth; | pchan->bone->xwidth = pchan_orig->bone->xwidth; | ||||
| pchan->bone->zwidth = pchan_orig->bone->zwidth; | pchan->bone->zwidth = pchan_orig->bone->zwidth; | ||||
| /* we assume X-axis flipping for now */ | /* we assume X-axis flipping for now */ | ||||
| pchan->curve_in_x = pchan_orig->curve_in_x * -1; | pchan->curve_in_x = pchan_orig->curve_in_x * -1; | ||||
| pchan->curve_out_x = pchan_orig->curve_out_x * -1; | pchan->curve_out_x = pchan_orig->curve_out_x * -1; | ||||
| pchan->roll1 = pchan_orig->roll1 * -1; // XXX? | pchan->roll1 = pchan_orig->roll1 * -1; // XXX? | ||||
| pchan->roll2 = pchan_orig->roll2 * -1; // XXX? | pchan->roll2 = pchan_orig->roll2 * -1; // XXX? | ||||
| float pchan_mtx_final[4][4]; | float pchan_mtx[4][4], pchan_mtx_final[4][4]; | ||||
| BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); | BKE_pchan_to_mat4(pchan_orig, pchan_mtx); | ||||
| mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); | mul_m4_m4m4(pchan_mtx_final, pchan_mtx, flip_mtx); | ||||
| mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); | mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); | ||||
| if (pid) { | if (pid) { | ||||
| mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); | mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); | ||||
| pid++; | |||||
| } | } | ||||
| BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); | BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); | ||||
| /* set flag to let autokeyframe know to keyframe the mirrred bone */ | /* in this case we can do target-less IK grabbing */ | ||||
Done Inline ActionsComments should be a sentence, so start with a captial letter and end with a period. sybren: Comments should be a sentence, so start with a captial letter and end with a period. | |||||
| pchan->bone->flag |= BONE_TRANSFORM_MIRROR; | if (t->mode == TFM_TRANSLATION) { | ||||
| bKinematicConstraint *data = has_targetless_ik(pchan); | |||||
| if (data) { | |||||
Done Inline Actionsif (data == NULL) continue; is clearer here IMO. sybren: `if (data == NULL) continue;` is clearer here IMO. | |||||
| mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); | |||||
| if (pid) { | |||||
| /* TODO: Realitve Mirror */ | |||||
Done Inline ActionsTODOs should have a name, indicating who to ask for more info about the TODO. sybren: TODOs should have a name, indicating who to ask for more info about the TODO. | |||||
| } | |||||
| data->flag |= CONSTRAINT_IK_AUTO; | |||||
| } | |||||
| } | |||||
| if (pid) { | |||||
| pid++; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* helper for recalcData() - for object transforms, typically in the 3D view */ | /* helper for recalcData() - for object transforms, typically in the 3D view */ | ||||
| static void recalcData_objects(TransInfo *t) | static void recalcData_objects(TransInfo *t) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (ob->mode == OB_MODE_POSE) { | else if (ob->mode == OB_MODE_POSE) { | ||||
| /* actually support TFM_BONESIZE in posemode as well */ | /* actually support TFM_BONESIZE in posemode as well */ | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | ||||
| bPose *pose = ob->pose; | bPose *pose = ob->pose; | ||||
| if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { | if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { | ||||
| pose_transform_mirror_update(ob, NULL); | pose_transform_mirror_update(t, tc, ob, NULL); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (t->flag & T_POSE) { | else if (t->flag & T_POSE) { | ||||
| GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates"); | GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates"); | ||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| Object *ob = tc->poseobj; | Object *ob = tc->poseobj; | ||||
| bPose *pose = ob->pose; | bPose *pose = ob->pose; | ||||
| if (pose->flag & POSE_MIRROR_EDIT) { | if (pose->flag & POSE_MIRROR_EDIT) { | ||||
| if (t->state != TRANS_CANCEL) { | if (t->state != TRANS_CANCEL) { | ||||
| PoseInitData_Mirror *pid = NULL; | PoseInitData_Mirror *pid = NULL; | ||||
| if (pose->flag & POSE_MIRROR_RELATIVE) { | if (pose->flag & POSE_MIRROR_RELATIVE) { | ||||
| pid = tc->custom.type.data; | pid = tc->custom.type.data; | ||||
| } | } | ||||
| pose_transform_mirror_update(ob, pid); | pose_transform_mirror_update(t, tc, ob, pid); | ||||
| } | } | ||||
| else { | else { | ||||
| restoreMirrorPoseBones(tc); | restoreMirrorPoseBones(tc); | ||||
| } | } | ||||
| } | } | ||||
| /* if animtimer is running, and the object already has animation data, | /* if animtimer is running, and the object already has animation data, | ||||
| * check if the auto-record feature means that we should record 'samples' | * check if the auto-record feature means that we should record 'samples' | ||||
| ▲ Show 20 Lines • Show All 1,501 Lines • Show Last 20 Lines | |||||
The fact that this doesn't happen when Auto IK is enabled should be documented here.