Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/transform/transform.h5
-rw-r--r--source/blender/editors/transform/transform_convert.c644
-rw-r--r--source/blender/editors/transform/transform_convert.h87
-rw-r--r--source/blender/editors/transform/transform_convert_action.c54
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c479
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c35
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c21
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c88
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c19
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c13
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c68
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c19
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c231
-rw-r--r--source/blender/editors/transform/transform_convert_node.c2
-rw-r--r--source/blender/editors/transform/transform_convert_object.c71
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c14
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c27
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c52
-rw-r--r--source/blender/editors/transform/transform_generics.c1132
20 files changed, 1559 insertions, 1522 deletions
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4097e0c8f8c..2f3af015a1e 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -427,6 +427,11 @@ typedef struct TransDataContainer {
typedef struct TransInfo {
TransDataContainer *data_container;
int data_container_len;
+
+ /** eTransConvertType
+ * TODO: It should be a member of TransDataContainer. */
+ int data_type;
+
/** Combine length of all #TransDataContainer.data_len
* Use to check if nothing is selected or if we have a single selection. */
int data_len_all;
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index cf60990d09c..59ba362c6f7 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
#include "BLI_string.h"
+#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -44,6 +46,7 @@
#include "BKE_gpencil.h"
#include "BKE_key.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_modifier.h"
@@ -68,6 +71,8 @@
#include "ED_node.h"
#include "ED_object.h"
#include "ED_particle.h"
+#include "ED_screen.h"
+#include "ED_screen_types.h"
#include "UI_view2d.h"
@@ -80,8 +85,11 @@
#include "DEG_depsgraph_build.h"
#include "transform.h"
-#include "transform_convert.h"
#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* Own include. */
+#include "transform_convert.h"
bool transform_mode_use_local_origins(const TransInfo *t)
{
@@ -2504,253 +2512,114 @@ void createTransData(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
- bool has_transform_context = true;
t->data_len_all = -1;
+ eTransConvertType convert_type = TC_NONE;
+
/* if tests must match recalcData for correct updates */
if (t->options & CTX_CURSOR) {
t->flag |= T_CURSOR;
if (t->spacetype == SPACE_IMAGE) {
- createTransCursor_image(t);
+ convert_type = TC_CURSOR_IMAGE;
}
else {
- createTransCursor_view3d(t);
+ convert_type = TC_CURSOR_VIEW3D;
}
- countAndCleanTransDataContainer(t);
}
else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
- createTransSculpt(t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_SCULPT;
}
else if (t->options & CTX_TEXTURE) {
t->flag |= T_TEXTURE;
-
- createTransTexspace(t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_OBJECT_TEXSPACE;
}
else if (t->options & CTX_EDGE) {
+ t->flag |= T_EDIT;
+ convert_type = TC_MESH_EDGES;
/* Multi object editing. */
initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
- t->flag |= T_EDIT;
-
- createTransEdge(t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
}
else if (t->options & CTX_GPENCIL_STROKES) {
t->options |= CTX_GPENCIL_STROKES;
t->flag |= T_POINTS | T_EDIT;
-
+ convert_type = TC_GPENCIL;
initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransGPencil(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
}
else if (t->spacetype == SPACE_IMAGE) {
t->flag |= T_POINTS | T_2D_EDIT;
if (t->options & CTX_MASK) {
-
- /* copied from below */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
+ convert_type = TC_MASKING_DATA;
}
else if (t->options & CTX_PAINT_CURVE) {
if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
+ convert_type = TC_PAINT_CURVE_VERTS;
}
}
else if (t->obedit_type == OB_MESH) {
-
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransUVs(C, t);
- countAndCleanTransDataContainer(t);
-
t->flag |= T_EDIT;
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
+ convert_type = TC_MESH_UV;
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
}
}
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
-
- createTransActionData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- /* don't do that, distance has been set in createTransActionData already */
- // set_prop_dist(t, false);
- sort_trans_data_dist(t);
- }
+ convert_type = TC_ACTION_DATA;
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
-
- createTransNlaData(C, t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_NLA_DATA;
}
else if (t->spacetype == SPACE_SEQ) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
-
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
- createTransSeqData(t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_SEQ_DATA;
}
else if (t->spacetype == SPACE_GRAPH) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
-
- createTransGraphEditData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- /* makes selected become first in array */
- sort_trans_data_selected_first(t);
-
- /* don't do that, distance has been set in createTransGraphEditData already */
- set_prop_dist(t, false);
-
- sort_trans_data_dist(t);
- }
+ convert_type = TC_GRAPH_EDIT_DATA;
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
-
- createTransNodeData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
+ convert_type = TC_NODE_DATA;
}
else if (t->spacetype == SPACE_CLIP) {
t->flag |= T_POINTS | T_2D_EDIT;
t->obedit_type = -1;
if (t->options & CTX_MOVIECLIP) {
- createTransTrackingData(C, t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_TRACKING_DATA;
}
else if (t->options & CTX_MASK) {
- /* copied from above */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
+ convert_type = TC_MASKING_DATA;
}
}
else if (t->obedit_type != -1) {
+ t->flag |= T_EDIT | T_POINTS;
+
/* Multi object editing. */
initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
if (t->obedit_type == OB_MESH) {
- createTransEditVerts(t);
+ convert_type = TC_MESH_VERTS;
}
else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
- createTransCurveVerts(t);
+ convert_type = TC_CURVE_VERTS;
}
else if (t->obedit_type == OB_LATTICE) {
- createTransLatticeVerts(t);
+ convert_type = TC_LATTICE_VERTS;
}
else if (t->obedit_type == OB_MBALL) {
- createTransMBallVerts(t);
+ convert_type = TC_MBALL_VERTS;
}
else if (t->obedit_type == OB_ARMATURE) {
t->flag &= ~T_PROP_EDIT;
- createTransArmatureVerts(t);
- }
- else {
- printf("edit type not implemented!\n");
- }
-
- countAndCleanTransDataContainer(t);
-
- t->flag |= T_EDIT | T_POINTS;
-
- if (t->data_len_all) {
- if (t->flag & T_PROP_EDIT) {
- if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
- sort_trans_data_selected_first(t);
- if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
- /* already calculated by editmesh_set_connectivity_distance */
- }
- else {
- set_prop_dist(t, 0);
- }
- sort_trans_data_dist(t);
- }
- else {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- if (ELEM(t->obedit_type, OB_CURVE)) {
- /* Needed because bezier handles can be partially selected
- * and are still added into transform data. */
- sort_trans_data_selected_first(t);
- }
- }
- }
-
- /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
- if (t->mode == TFM_BONESIZE) {
- t->flag &= ~(T_EDIT | T_POINTS);
- t->flag |= T_POSE;
- t->obedit_type = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->poseobj = tc->obedit;
- tc->obedit = NULL;
- }
+ convert_type = TC_ARMATURE_VERTS;
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
@@ -2761,13 +2630,11 @@ void createTransData(bContext *C, TransInfo *t)
/* Multi object editing. */
initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
+ convert_type = TC_POSE;
}
else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
- has_transform_context = false;
Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob);
if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
@@ -2778,33 +2645,20 @@ void createTransData(bContext *C, TransInfo *t)
objects[0] = ob_armature;
uint objects_len = 1;
initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
- has_transform_context = true;
+ convert_type = TC_POSE;
}
}
}
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) {
- createTransParticleVerts(C, t);
- countAndCleanTransDataContainer(t);
t->flag |= T_POINTS;
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
+ convert_type = TC_PARTICLE_VERTS;
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
t->flag |= T_POINTS | T_2D_EDIT;
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
+ convert_type = TC_PAINT_CURVE_VERTS;
}
}
else if ((ob) && (ELEM(ob->mode,
@@ -2813,7 +2667,6 @@ void createTransData(bContext *C, TransInfo *t)
OB_MODE_WEIGHT_GPENCIL,
OB_MODE_VERTEX_GPENCIL))) {
/* In grease pencil all transformations must be canceled if not Object or Edit. */
- has_transform_context = false;
}
else {
/* Needed for correct Object.obmat after duplication, see: T62135. */
@@ -2826,16 +2679,8 @@ void createTransData(bContext *C, TransInfo *t)
t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN;
}
- createTransObject(C, t);
- countAndCleanTransDataContainer(t);
t->flag |= T_OBJECT;
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- // selected objects are already first, no need to presort
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
-
/* Check if we're transforming the camera from the camera */
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
View3D *v3d = t->view;
@@ -2850,18 +2695,417 @@ void createTransData(bContext *C, TransInfo *t)
t->flag |= T_CAMERA;
}
}
+ convert_type = TC_OBJECT;
}
- /* Check that 'countAndCleanTransDataContainer' ran. */
- if (has_transform_context) {
- BLI_assert(t->data_len_all != -1);
+ t->data_type = convert_type;
+ bool init_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ switch (convert_type) {
+ case TC_ACTION_DATA:
+ createTransActionData(C, t);
+ break;
+ case TC_POSE:
+ createTransPose(t);
+ init_prop_edit = false;
+ break;
+ case TC_ARMATURE_VERTS:
+ createTransArmatureVerts(t);
+ break;
+ case TC_CURSOR_IMAGE:
+ createTransCursor_image(t);
+ init_prop_edit = false;
+ break;
+ case TC_CURSOR_VIEW3D:
+ createTransCursor_view3d(t);
+ init_prop_edit = false;
+ break;
+ case TC_CURVE_VERTS:
+ createTransCurveVerts(t);
+ break;
+ case TC_GRAPH_EDIT_DATA:
+ createTransGraphEditData(C, t);
+ break;
+ case TC_GPENCIL:
+ createTransGPencil(C, t);
+ break;
+ case TC_LATTICE_VERTS:
+ createTransLatticeVerts(t);
+ break;
+ case TC_MASKING_DATA:
+ createTransMaskingData(C, t);
+ break;
+ case TC_MBALL_VERTS:
+ createTransMBallVerts(t);
+ break;
+ case TC_MESH_VERTS:
+ createTransEditVerts(t);
+ break;
+ case TC_MESH_EDGES:
+ createTransEdge(t);
+ break;
+ case TC_MESH_UV:
+ createTransUVs(C, t);
+ break;
+ case TC_NLA_DATA:
+ createTransNlaData(C, t);
+ init_prop_edit = false;
+ break;
+ case TC_NODE_DATA:
+ createTransNodeData(t);
+ break;
+ case TC_OBJECT:
+ createTransObject(C, t);
+ break;
+ case TC_OBJECT_TEXSPACE:
+ createTransTexspace(t);
+ init_prop_edit = false;
+ break;
+ case TC_PAINT_CURVE_VERTS:
+ createTransPaintCurveVerts(C, t);
+ init_prop_edit = false;
+ break;
+ case TC_PARTICLE_VERTS:
+ createTransParticleVerts(C, t);
+ break;
+ case TC_SCULPT:
+ createTransSculpt(t);
+ init_prop_edit = false;
+ break;
+ case TC_SEQ_DATA:
+ createTransSeqData(t);
+ init_prop_edit = false;
+ break;
+ case TC_TRACKING_DATA:
+ createTransTrackingData(C, t);
+ init_prop_edit = false;
+ break;
+ case TC_NONE:
+ default:
+ printf("edit type not implemented!\n");
+ BLI_assert(t->data_len_all == -1);
+ t->data_len_all = 0;
+ return;
+ }
+
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && init_prop_edit) {
+ if (convert_type == TC_OBJECT) {
+ /* Selected objects are already first, no need to presort. */
+ }
+ else {
+ sort_trans_data_selected_first(t);
+ }
+
+ if (ELEM(convert_type, TC_ACTION_DATA, TC_GRAPH_EDIT_DATA)) {
+ /* Distance has already been set. */
+ }
+ else if (convert_type == TC_MESH_VERTS) {
+ if (t->flag & T_PROP_CONNECTED) {
+ /* Already calculated by editmesh_set_connectivity_distance. */
+ }
+ else {
+ set_prop_dist(t, false);
+ }
+ }
+ else if (convert_type == TC_CURVE_VERTS && t->obedit_type == OB_CURVE) {
+ set_prop_dist(t, false);
+ }
+ else {
+ set_prop_dist(t, true);
+ }
+
+ sort_trans_data_dist(t);
}
else {
- BLI_assert(t->data_len_all == -1);
- t->data_len_all = 0;
+ if (ELEM(t->obedit_type, OB_CURVE)) {
+ /* Needed because bezier handles can be partially selected
+ * and are still added into transform data. */
+ sort_trans_data_selected_first(t);
+ }
+ }
+
+ /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
+ if (t->mode == TFM_BONESIZE) {
+ t->flag &= ~(T_EDIT | T_POINTS);
+ t->flag |= T_POSE;
+ t->obedit_type = -1;
+ t->data_type = TC_NONE;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->poseobj = tc->obedit;
+ tc->obedit = NULL;
+ }
}
BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Data Recalc/Flush
+ * \{ */
+
+void clipMirrorModifier(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->obedit;
+ ModifierData *md = ob->modifiers.first;
+ float tolerance[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+
+ for (; md; md = md->next) {
+ if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ axis = 0;
+ if (mmd->flag & MOD_MIR_AXIS_X) {
+ axis |= 1;
+ tolerance[0] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Y) {
+ axis |= 2;
+ tolerance[1] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Z) {
+ axis |= 4;
+ tolerance[2] = mmd->tolerance;
+ }
+ if (axis) {
+ float mtx[4][4], imtx[4][4];
+ int i;
+
+ if (mmd->mirror_ob) {
+ float obinv[4][4];
+
+ invert_m4_m4(obinv, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, obinv, ob->obmat);
+ invert_m4_m4(imtx, mtx);
+ }
+
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ int clip;
+ float loc[3], iloc[3];
+
+ if (td->loc == NULL) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ copy_v3_v3(loc, td->loc);
+ copy_v3_v3(iloc, td->iloc);
+
+ if (mmd->mirror_ob) {
+ mul_m4_v3(mtx, loc);
+ mul_m4_v3(mtx, iloc);
+ }
+
+ clip = 0;
+ if (axis & 1) {
+ if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) {
+ loc[0] = 0.0f;
+ clip = 1;
+ }
+ }
+
+ if (axis & 2) {
+ if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) {
+ loc[1] = 0.0f;
+ clip = 1;
+ }
+ }
+ if (axis & 4) {
+ if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) {
+ loc[2] = 0.0f;
+ clip = 1;
+ }
+ }
+ if (clip) {
+ if (mmd->mirror_ob) {
+ mul_m4_v3(imtx, loc);
+ }
+ copy_v3_v3(td->loc, loc);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* for the realtime animation recording feature, handle overlapping data */
+void animrecord_check_state(TransInfo *t, struct Object *ob)
+{
+ Scene *scene = t->scene;
+ ID *id = &ob->id;
+ wmTimer *animtimer = t->animtimer;
+ ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, scene, id, sad)) {
+ return;
+ }
+
+ /* check if we need a new strip if:
+ * - if animtimer is running
+ * - we're not only keying for available channels
+ * - the option to add new actions for each round is not enabled
+ */
+ if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0 &&
+ (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
+ /* if playback has just looped around,
+ * we need to add a new NLA track+strip to allow a clean pass to occur */
+ if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
+
+ /* perform push-down manually with some differences
+ * NOTE: BKE_nla_action_pushdown() sync warning...
+ */
+ if ((adt->action) && !(adt->flag & ADT_NLA_EDIT_ON)) {
+ float astart, aend;
+
+ /* only push down if action is more than 1-2 frames long */
+ calc_action_range(adt->action, &astart, &aend, 1);
+ if (aend > astart + 2.0f) {
+ NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
+
+ /* clear reference to action now that we've pushed it onto the stack */
+ id_us_min(&adt->action->id);
+ adt->action = NULL;
+
+ /* adjust blending + extend so that they will behave correctly */
+ strip->extendmode = NLASTRIP_EXTEND_NOTHING;
+ strip->flag &= ~(NLASTRIP_FLAG_AUTO_BLENDS | NLASTRIP_FLAG_SELECT |
+ NLASTRIP_FLAG_ACTIVE);
+
+ /* copy current "action blending" settings from adt to the strip,
+ * as it was keyframed with these settings, so omitting them will
+ * change the effect [T54766]
+ */
+ if (is_first == false) {
+ strip->blendmode = adt->act_blendmode;
+ strip->influence = adt->act_influence;
+
+ if (adt->act_influence < 1.0f) {
+ /* enable "user-controlled" influence (which will insert a default keyframe)
+ * so that the influence doesn't get lost on the new update
+ *
+ * NOTE: An alternative way would have been to instead hack the influence
+ * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
+ * is disabled but auto-blending isn't being used. However, that approach
+ * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
+ * so it's better to just do it this way.
+ */
+ strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+ BKE_nlastrip_validate_fcurves(strip);
+ }
+ }
+
+ /* also, adjust the AnimData's action extend mode to be on
+ * 'nothing' so that previous result still play
+ */
+ adt->act_extendmode = NLASTRIP_EXTEND_NOTHING;
+ }
+ }
+ }
+ }
+}
+
+static void recalcData_cursor(TransInfo *t)
+{
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+static void recalcData_obedit(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ }
+ }
+}
+
+/* called for updating while transform acts, once per redraw */
+void recalcData(TransInfo *t)
+{
+ switch (t->data_type) {
+ case TC_ACTION_DATA:
+ recalcData_actedit(t);
+ break;
+ case TC_POSE:
+ recalcData_pose(t);
+ break;
+ case TC_ARMATURE_VERTS:
+ recalcData_edit_armature(t);
+ break;
+ case TC_CURVE_VERTS:
+ recalcData_curve(t);
+ break;
+ case TC_CURSOR_IMAGE:
+ case TC_CURSOR_VIEW3D:
+ recalcData_cursor(t);
+ break;
+ case TC_GRAPH_EDIT_DATA:
+ recalcData_graphedit(t);
+ break;
+ case TC_GPENCIL:
+ recalcData_gpencil_strokes(t);
+ break;
+ case TC_MASKING_DATA:
+ recalcData_mask_common(t);
+ break;
+ case TC_MESH_VERTS:
+ case TC_MESH_EDGES:
+ recalcData_mesh(t);
+ break;
+ case TC_MESH_UV:
+ recalcData_uv(t);
+ break;
+ case TC_NLA_DATA:
+ recalcData_nla(t);
+ break;
+ case TC_NODE_DATA:
+ flushTransNodes(t);
+ break;
+ case TC_OBJECT:
+ case TC_OBJECT_TEXSPACE:
+ recalcData_objects(t);
+ break;
+ case TC_PAINT_CURVE_VERTS:
+ flushTransPaintCurve(t);
+ break;
+ case TC_SCULPT:
+ recalcData_sculpt(t);
+ break;
+ case TC_SEQ_DATA:
+ recalcData_sequencer(t);
+ break;
+ case TC_TRACKING_DATA:
+ recalcData_tracking(t);
+ break;
+ case TC_MBALL_VERTS:
+ case TC_LATTICE_VERTS:
+ recalcData_obedit(t);
+ break;
+ case TC_PARTICLE_VERTS:
+ recalcData_particles(t);
+ break;
+ case TC_NONE:
+ default:
+ break;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index bbf6bfd7f55..4a6d56f6630 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -52,72 +52,71 @@ void autokeyframe_pose(
bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
int special_transform_moving(TransInfo *t);
-void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
void clipUVData(TransInfo *t);
-
-/* transform_convert_action.c */
-void flushTransIntFrameActionData(TransInfo *t);
-
-/* transform_convert_armature.c */
-void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob);
-void restoreMirrorPoseBones(TransDataContainer *tc);
-void restoreBones(TransDataContainer *tc);
-
-/* transform_convert_graph.c */
-void flushTransGraphData(TransInfo *t);
-
-/* transform_convert_mask.c */
-void flushTransMasking(TransInfo *t);
+void recalcData(TransInfo *t);
/* transform_convert_mesh.c */
void trans_mesh_customdata_correction_init(TransInfo *t);
void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final);
-/* transform_convert_mesh_uv.c */
-void flushTransUVs(TransInfo *t);
-
-/* transform_convert_node.c */
-void flushTransNodes(TransInfo *t);
-
-/* transform_convert_object.c */
-void trans_obdata_in_obmode_update_all(struct TransInfo *t);
-void trans_obchild_in_obmode_update_all(struct TransInfo *t);
-
-/* transform_convert_paintcurve.c */
-void flushTransPaintCurve(TransInfo *t);
-
-/* transform_convert_particle.c */
-void flushTransParticles(TransInfo *t);
-
/* transform_convert_sequencer.c */
-void flushTransSeq(TransInfo *t);
int transform_convert_sequencer_get_snap_bound(TransInfo *t);
-/* transform_convert_tracking.c */
-void flushTransTracking(TransInfo *t);
-
/********************* intern **********************/
+typedef enum eTransConvertType {
+ TC_NONE = 0,
+ TC_ACTION_DATA,
+ TC_POSE,
+ TC_ARMATURE_VERTS,
+ TC_CURSOR_IMAGE,
+ TC_CURSOR_VIEW3D,
+ TC_CURVE_VERTS,
+ TC_GRAPH_EDIT_DATA,
+ TC_GPENCIL,
+ TC_LATTICE_VERTS,
+ TC_MASKING_DATA,
+ TC_MBALL_VERTS,
+ TC_MESH_VERTS,
+ TC_MESH_EDGES,
+ TC_MESH_UV,
+ TC_NLA_DATA,
+ TC_NODE_DATA,
+ TC_OBJECT,
+ TC_OBJECT_TEXSPACE,
+ TC_PAINT_CURVE_VERTS,
+ TC_PARTICLE_VERTS,
+ TC_SCULPT,
+ TC_SEQ_DATA,
+ TC_TRACKING_DATA,
+} eTransConvertType;
+
/* transform_convert.c */
bool transform_mode_use_local_origins(const TransInfo *t);
void transform_around_single_fallback(TransInfo *t);
+void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail);
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
+void clipMirrorModifier(TransInfo *t);
+void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
void createTransActionData(bContext *C, TransInfo *t);
+void recalcData_actedit(TransInfo *t);
/* transform_convert_armature.c */
struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan);
void createTransPose(TransInfo *t);
void createTransArmatureVerts(TransInfo *t);
+void recalcData_edit_armature(TransInfo *t);
+void recalcData_pose(TransInfo *t);
/* transform_convert_cursor.c */
void createTransCursor_image(TransInfo *t);
@@ -125,55 +124,69 @@ void createTransCursor_view3d(TransInfo *t);
/* transform_convert_curve.c */
void createTransCurveVerts(TransInfo *t);
+void recalcData_curve(TransInfo *t);
/* transform_convert_graph.c */
void createTransGraphEditData(bContext *C, TransInfo *t);
+void recalcData_graphedit(TransInfo *t);
/* transform_convert_gpencil.c */
void createTransGPencil(bContext *C, TransInfo *t);
+void recalcData_gpencil_strokes(TransInfo *t);
/* transform_convert_lattice.c */
void createTransLatticeVerts(TransInfo *t);
/* transform_convert_mask.c */
void createTransMaskingData(bContext *C, TransInfo *t);
+void recalcData_mask_common(TransInfo *t);
/* transform_convert_mball.c */
void createTransMBallVerts(TransInfo *t);
/* transform_convert_mesh.c */
void createTransEditVerts(TransInfo *t);
+void recalcData_mesh(TransInfo *t);
/* transform_convert_mesh_edge.c */
void createTransEdge(TransInfo *t);
/* transform_convert_mesh_uv.c */
void createTransUVs(bContext *C, TransInfo *t);
+void recalcData_uv(TransInfo *t);
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);
+void recalcData_nla(TransInfo *t);
/* transform_convert_node.c */
-void createTransNodeData(bContext *UNUSED(C), TransInfo *t);
+void createTransNodeData(TransInfo *t);
+void flushTransNodes(TransInfo *t);
/* transform_convert_object.c */
void clear_trans_object_base_flags(TransInfo *t);
void createTransObject(bContext *C, TransInfo *t);
void createTransTexspace(TransInfo *t);
+void recalcData_objects(TransInfo *t);
/* transform_convert_paintcurve.c */
void createTransPaintCurveVerts(bContext *C, TransInfo *t);
+void flushTransPaintCurve(TransInfo *t);
/* transform_convert_particle.c */
void createTransParticleVerts(bContext *C, TransInfo *t);
+void recalcData_particles(TransInfo *t);
/* transform_convert_sculpt.c */
void createTransSculpt(TransInfo *t);
+void recalcData_sculpt(TransInfo *t);
-/* transform_convert_sequence.c */
+/* transform_convert_sequencer.c */
void createTransSeqData(TransInfo *t);
+void recalcData_sequencer(TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
void cancelTransTracking(TransInfo *t);
+void recalcData_tracking(TransInfo *t);
#endif
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 21ef1539911..87256764e65 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -555,7 +555,7 @@ void createTransActionData(bContext *C, TransInfo *t)
* \{ */
/* This function helps flush transdata written to tempdata into the gp-frames */
-void flushTransIntFrameActionData(TransInfo *t)
+static void flushTransIntFrameActionData(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
tGPFtransdata *tfd = tc->custom.type.data;
@@ -566,4 +566,56 @@ void flushTransIntFrameActionData(TransInfo *t)
}
}
+/* helper for recalcData() - for Action Editor transforms */
+void recalcData_actedit(TransInfo *t)
+{
+ ViewLayer *view_layer = t->view_layer;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
+
+ bAnimContext ac = {NULL};
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* initialize relevant anim-context 'context' data from TransInfo data */
+ /* NOTE: sync this with the code in ANIM_animdata_get_context() */
+ ac.bmain = CTX_data_main(t->context);
+ ac.scene = t->scene;
+ ac.view_layer = t->view_layer;
+ ac.obact = OBACT(view_layer);
+ ac.area = t->area;
+ ac.region = t->region;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
+ ac.regiontype = (t->region) ? t->region->regiontype : 0;
+
+ ANIM_animdata_context_getdata(&ac);
+
+ /* perform flush */
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ /* flush transform values back to actual coordinates */
+ flushTransIntFrameActionData(t);
+ }
+
+ if (ac.datatype != ANIMCONT_MASK) {
+ /* Get animdata blocks visible in editor,
+ * assuming that these will be the ones where things changed. */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* just tag these animdata-blocks to recalc, assuming that some data there changed
+ * BUT only do this if realtime updates are enabled
+ */
+ if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* set refresh tags for objects using this animation */
+ ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
+ }
+ }
+
+ /* now free temp channels */
+ ANIM_animdata_freelist(&anim_data);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 35bb7e3f0d8..92c79dc2b03 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -39,11 +40,15 @@
#include "BIK_api.h"
#include "ED_armature.h"
+#include "ED_keyframing.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
#include "transform_convert.h"
typedef struct BoneInitData {
@@ -545,97 +550,6 @@ static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
}
}
-/**
- * if pose bone (partial) selected, copy data.
- * context; posemode armature, with mirror editing enabled.
- */
-void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob)
-{
- float flip_mtx[4][4];
- unit_m4(flip_mtx);
- flip_mtx[0][0] = -1;
-
- LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) {
- /* Clear the MIRROR flag from previous runs. */
- pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
- }
-
- bPose *pose = ob->pose;
- PoseInitData_Mirror *pid = NULL;
- if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) {
- pid = tc->custom.type.data;
- }
-
- TransData *td = tc->data;
- 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. */
- bPoseChannel *pchan = BKE_pose_channel_get_mirrored(pose, pchan_orig->name);
- if (pchan == NULL) {
- continue;
- }
-
- /* Also do bbone scaling. */
- pchan->bone->xwidth = pchan_orig->bone->xwidth;
- pchan->bone->zwidth = pchan_orig->bone->zwidth;
-
- /* We assume X-axis flipping for now. */
- pchan->curve_in_x = pchan_orig->curve_in_x * -1;
- pchan->curve_out_x = pchan_orig->curve_out_x * -1;
- pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
- pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
-
- float pchan_mtx_final[4][4];
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
- mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
- mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
- if (pid) {
- mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
- }
- BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
-
- /* Set flag to let autokeyframe know to keyframe the mirrred bone. */
- pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
-
- /* In this case we can do target-less IK grabbing. */
- if (t->mode == TFM_TRANSLATION) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data == NULL) {
- continue;
- }
- mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
- if (pid) {
- /* TODO(germano): Realitve Mirror support */
- }
- data->flag |= CONSTRAINT_IK_AUTO;
- /* Add a temporary auto IK constraint here, as we will only temporarily active this
- * target-less bone during transform. (Target-less IK constraints are treated as if they are
- * disabled unless they are transformed) */
- add_temporary_ik_constraint(pchan, data);
- Main *bmain = CTX_data_main(t->context);
- update_deg_with_temporary_ik(bmain, ob);
- }
-
- if (pid) {
- pid++;
- }
- }
-}
-
-void restoreMirrorPoseBones(TransDataContainer *tc)
-{
- bPose *pose = tc->poseobj->pose;
-
- if (!(pose->flag & POSE_MIRROR_EDIT)) {
- return;
- }
-
- for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
- pose_mirror_info_restore(pid);
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -793,55 +707,6 @@ void createTransPose(TransInfo *t)
t->flag &= ~T_PROP_EDIT_ALL;
}
-void restoreBones(TransDataContainer *tc)
-{
- bArmature *arm;
- BoneInitData *bid = tc->custom.type.data;
- EditBone *ebo;
-
- if (tc->obedit) {
- arm = tc->obedit->data;
- }
- else {
- BLI_assert(tc->poseobj != NULL);
- arm = tc->poseobj->data;
- }
-
- while (bid->bone) {
- ebo = bid->bone;
-
- ebo->dist = bid->dist;
- ebo->rad_head = bid->rad_head;
- ebo->rad_tail = bid->rad_tail;
- ebo->roll = bid->roll;
- ebo->xwidth = bid->xwidth;
- ebo->zwidth = bid->zwidth;
- copy_v3_v3(ebo->head, bid->head);
- copy_v3_v3(ebo->tail, bid->tail);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *ebo_child;
-
- /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
- for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
- if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
- copy_v3_v3(ebo_child->head, ebo->tail);
- ebo_child->rad_head = ebo->rad_tail;
- }
- }
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
- EditBone *parent = ebo->parent;
- copy_v3_v3(parent->tail, ebo->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
-
- bid++;
- }
-}
-
void createTransArmatureVerts(TransInfo *t)
{
t->data_len_all = 0;
@@ -1097,3 +962,337 @@ void createTransArmatureVerts(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Data Edit Armature
+ * \{ */
+
+static void restoreBones(TransDataContainer *tc)
+{
+ bArmature *arm;
+ BoneInitData *bid = tc->custom.type.data;
+ EditBone *ebo;
+
+ if (tc->obedit) {
+ arm = tc->obedit->data;
+ }
+ else {
+ BLI_assert(tc->poseobj != NULL);
+ arm = tc->poseobj->data;
+ }
+
+ while (bid->bone) {
+ ebo = bid->bone;
+
+ ebo->dist = bid->dist;
+ ebo->rad_head = bid->rad_head;
+ ebo->rad_tail = bid->rad_tail;
+ ebo->roll = bid->roll;
+ ebo->xwidth = bid->xwidth;
+ ebo->zwidth = bid->zwidth;
+ copy_v3_v3(ebo->head, bid->head);
+ copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
+ bid++;
+ }
+}
+
+void recalcData_edit_armature(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ EditBone *ebo, *ebo_parent;
+ TransData *td = tc->data;
+ int i;
+
+ /* Ensure all bones are correctly adjusted */
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
+
+ if (ebo_parent) {
+ /* If this bone has a parent tip that has been moved */
+ if (ebo_parent->flag & BONE_TIPSEL) {
+ copy_v3_v3(ebo->head, ebo_parent->tail);
+ if (t->mode == TFM_BONE_ENVELOPE) {
+ ebo->rad_head = ebo_parent->rad_tail;
+ }
+ }
+ /* If this bone has a parent tip that has NOT been moved */
+ else {
+ copy_v3_v3(ebo_parent->tail, ebo->head);
+ if (t->mode == TFM_BONE_ENVELOPE) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
+ }
+ }
+
+ /* on extrude bones, oldlength==0.0f, so we scale radius of points */
+ ebo->length = len_v3v3(ebo->head, ebo->tail);
+ if (ebo->oldlength == 0.0f) {
+ ebo->rad_head = 0.25f * ebo->length;
+ ebo->rad_tail = 0.10f * ebo->length;
+ ebo->dist = 0.25f * ebo->length;
+ if (ebo->parent) {
+ if (ebo->rad_head > ebo->parent->rad_tail) {
+ ebo->rad_head = ebo->parent->rad_tail;
+ }
+ }
+ }
+ else if (t->mode != TFM_BONE_ENVELOPE) {
+ /* if bones change length, lets do that for the deform distance as well */
+ ebo->dist *= ebo->length / ebo->oldlength;
+ ebo->rad_head *= ebo->length / ebo->oldlength;
+ ebo->rad_tail *= ebo->length / ebo->oldlength;
+ ebo->oldlength = ebo->length;
+
+ if (ebo_parent) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
+ }
+ }
+
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
+ /* fix roll */
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->extra) {
+ float vec[3], up_axis[3];
+ float qrot[4];
+ float roll;
+
+ ebo = td->extra;
+
+ if (t->state == TRANS_CANCEL) {
+ /* restore roll */
+ ebo->roll = td->ival;
+ }
+ else {
+ copy_v3_v3(up_axis, td->axismtx[2]);
+
+ sub_v3_v3v3(vec, ebo->tail, ebo->head);
+ normalize_v3(vec);
+ rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
+ mul_qt_v3(qrot, up_axis);
+
+ /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
+ roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
+ ebo->roll = angle_compat_rad(roll, td->ival);
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ if (t->state != TRANS_CANCEL) {
+ ED_armature_edit_transform_mirror_update(tc->obedit);
+ }
+ else {
+ restoreBones(tc);
+ }
+ }
+
+ /* Tag for redraw/invalidate overlay cache. */
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Data Pose
+ * \{ */
+
+/**
+ * if pose bone (partial) selected, copy data.
+ * context; posemode armature, with mirror editing enabled.
+ */
+static void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob)
+{
+ float flip_mtx[4][4];
+ unit_m4(flip_mtx);
+ flip_mtx[0][0] = -1;
+
+ LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
+ bPose *pose = ob->pose;
+ PoseInitData_Mirror *pid = NULL;
+ if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) {
+ pid = tc->custom.type.data;
+ }
+
+ TransData *td = tc->data;
+ 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. */
+ bPoseChannel *pchan = BKE_pose_channel_get_mirrored(pose, pchan_orig->name);
+ if (pchan == NULL) {
+ continue;
+ }
+
+ /* Also do bbone scaling. */
+ pchan->bone->xwidth = pchan_orig->bone->xwidth;
+ pchan->bone->zwidth = pchan_orig->bone->zwidth;
+
+ /* We assume X-axis flipping for now. */
+ pchan->curve_in_x = pchan_orig->curve_in_x * -1;
+ pchan->curve_out_x = pchan_orig->curve_out_x * -1;
+ pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
+ pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
+
+ float pchan_mtx_final[4][4];
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
+ mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
+ if (pid) {
+ mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
+ }
+ BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+
+ /* Set flag to let autokeyframe know to keyframe the mirrred bone. */
+ pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+
+ /* In this case we can do target-less IK grabbing. */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data == NULL) {
+ continue;
+ }
+ mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
+ if (pid) {
+ /* TODO(germano): Realitve Mirror support */
+ }
+ data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * target-less bone during transform. (Target-less IK constraints are treated as if they are
+ * disabled unless they are transformed) */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
+ }
+
+ if (pid) {
+ pid++;
+ }
+ }
+}
+
+static void restoreMirrorPoseBones(TransDataContainer *tc)
+{
+ bPose *pose = tc->poseobj->pose;
+
+ if (!(pose->flag & POSE_MIRROR_EDIT)) {
+ return;
+ }
+
+ for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
+ pose_mirror_info_restore(pid);
+ }
+}
+
+void recalcData_pose(TransInfo *t)
+{
+ if (t->mode == TFM_BONESIZE) {
+ /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
+ * in pose mode (to use bone orientation matrix),
+ * in that case we have to do mirroring as well. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+ bArmature *arm = ob->data;
+ if (ob->mode == OB_MODE_EDIT) {
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ if (t->state != TRANS_CANCEL) {
+ ED_armature_edit_transform_mirror_update(ob);
+ }
+ else {
+ restoreBones(tc);
+ }
+ }
+ }
+ else if (ob->mode == OB_MODE_POSE) {
+ /* actually support TFM_BONESIZE in posemode as well */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ bPose *pose = ob->pose;
+ if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) {
+ pose_transform_mirror_update(t, tc, ob);
+ }
+ }
+ }
+ }
+ else {
+ GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+ bPose *pose = ob->pose;
+
+ if (pose->flag & POSE_MIRROR_EDIT) {
+ if (t->state != TRANS_CANCEL) {
+ pose_transform_mirror_update(t, tc, ob);
+ }
+ else {
+ restoreMirrorPoseBones(tc);
+ }
+ }
+
+ /* if animtimer is running, and the object already has animation data,
+ * check if the auto-record feature means that we should record 'samples'
+ * (i.e. un-editable animation values)
+ *
+ * context is needed for keying set poll() functions.
+ */
+
+ /* TODO: autokeyframe calls need some setting to specify to add samples
+ * (FPoints) instead of keyframes? */
+ if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
+ int targetless_ik =
+ (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
+
+ animrecord_check_state(t, ob);
+ autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
+ }
+
+ if (motionpath_need_update_pose(t->scene, ob)) {
+ BLI_gset_insert(motionpath_updates, ob);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* Update motion paths once for all transformed bones in an object. */
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, motionpath_updates) {
+ Object *ob = BLI_gsetIterator_getKey(&gs_iter);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
+ }
+ BLI_gset_free(motionpath_updates, NULL);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 1f113a36a89..c5e1e59b9e6 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -32,6 +32,9 @@
#include "BKE_curve.h"
#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
@@ -419,4 +422,36 @@ void createTransCurveVerts(TransInfo *t)
#undef SEL_F3
}
+void recalcData_curve(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ clipMirrorModifier(t);
+ applyProject(t);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Curve *cu = tc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ Nurb *nu = nurbs->first;
+
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+
+ if (t->state == TRANS_CANCEL) {
+ while (nu) {
+ /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
+ BKE_nurb_handles_calc(nu);
+ nu = nu->next;
+ }
+ }
+ else {
+ /* Normal updating */
+ while (nu) {
+ BKE_nurb_test_2d(nu);
+ BKE_nurb_handles_calc(nu);
+ nu = nu->next;
+ }
+ }
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 00b0eab90cd..2bfce9f8418 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -25,11 +25,13 @@
#include "MEM_guardedalloc.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
#include "ED_gpencil.h"
@@ -376,4 +378,23 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
+/* force recalculation of triangles during transformation */
+void recalcData_gpencil_strokes(TransInfo *t)
+{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ GHash *strokes = BLI_ghash_ptr_new(__func__);
+
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ bGPDstroke *gps = td->extra;
+
+ if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) {
+ BLI_ghash_insert(strokes, gps, gps);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ }
+ }
+ BLI_ghash_free(strokes, NULL, NULL);
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index f6f0dd3c491..0e77c991300 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -634,10 +634,28 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
*
* \{ */
+static bool fcu_test_selected(FCurve *fcu)
+{
+ BezTriple *bezt = fcu->bezt;
+ uint i;
+
+ if (bezt == NULL) { /* ignore baked */
+ return 0;
+ }
+
+ for (i = 0; i < fcu->totvert; i++, bezt++) {
+ if (BEZT_ISSEL_ANY(bezt)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* this function is called on recalcData to apply the transforms applied
* to the transdata on to the actual keyframe data
*/
-void flushTransGraphData(TransInfo *t)
+static void flushTransGraphData(TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
TransData *td;
@@ -733,4 +751,72 @@ void flushTransGraphData(TransInfo *t)
}
}
+/* helper for recalcData() - for Graph Editor transforms */
+void recalcData_graphedit(TransInfo *t)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
+ ViewLayer *view_layer = t->view_layer;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimContext ac = {NULL};
+ int filter;
+
+ bAnimListElem *ale;
+ int dosort = 0;
+
+ /* initialize relevant anim-context 'context' data from TransInfo data */
+ /* NOTE: sync this with the code in ANIM_animdata_get_context() */
+ ac.bmain = CTX_data_main(t->context);
+ ac.scene = t->scene;
+ ac.view_layer = t->view_layer;
+ ac.obact = OBACT(view_layer);
+ ac.area = t->area;
+ ac.region = t->region;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
+ ac.regiontype = (t->region) ? t->region->regiontype : 0;
+
+ ANIM_animdata_context_getdata(&ac);
+
+ /* do the flush first */
+ flushTransGraphData(t);
+
+ /* get curves to check if a re-sort is needed */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* now test if there is a need to re-sort */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* ignore FC-Curves without any selected verts */
+ if (!fcu_test_selected(fcu)) {
+ continue;
+ }
+
+ /* watch it: if the time is wrong: do not correct handles yet */
+ if (test_time_fcurve(fcu)) {
+ dosort++;
+ }
+ else {
+ calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG);
+ }
+
+ /* set refresh tags for objects using this animation,
+ * BUT only if realtime updates are enabled
+ */
+ if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0) {
+ ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
+ }
+ }
+
+ /* do resort and other updates? */
+ if (dosort) {
+ remake_graph_transdata(t, &anim_data);
+ }
+
+ /* now free temp channels */
+ ANIM_animdata_freelist(&anim_data);
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
index 57d0f707971..b73a4c1ab2d 100644
--- a/source/blender/editors/transform/transform_convert_lattice.c
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -29,8 +29,12 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_lattice.h"
#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
@@ -109,4 +113,19 @@ void createTransLatticeVerts(TransInfo *t)
}
}
+void recalcData_lattice(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Lattice *la = tc->obedit->data;
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ if (la->editlatt->latt->flag & LT_OUTSIDE) {
+ outside_lattice(la->editlatt->latt);
+ }
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 6c743da3e65..07b8495d3bd 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -396,11 +396,11 @@ void createTransMaskingData(bContext *C, TransInfo *t)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Masking Transform Flush
+/** \name Recalc TransData Masking
*
* \{ */
-void flushTransMasking(TransInfo *t)
+static void flushTransMasking(TransInfo *t)
{
TransData2D *td;
TransDataMasking *tdm;
@@ -439,4 +439,13 @@ void flushTransMasking(TransInfo *t)
}
}
+void recalcData_mask_common(TransInfo *t)
+{
+ Mask *mask = CTX_data_edit_mask(t->context);
+
+ flushTransMasking(t);
+
+ DEG_id_tag_update(&mask->id, 0);
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index cddb90cb167..6546f257132 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -44,9 +44,12 @@
#include "DEG_depsgraph_query.h"
#include "transform.h"
-#include "transform_convert.h"
+#include "transform_mode.h"
#include "transform_snap.h"
+/* Own include. */
+#include "transform_convert.h"
+
/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */
#define TRANSFORM_MAXDIST_MIRROR 0.00002f
@@ -1302,3 +1305,66 @@ void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Mesh Data
+ *
+ * \{ */
+
+static void transform_apply_to_mirror(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->mirror.use_mirror_any) {
+ int i;
+ TransData *td;
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
+ if (td->flag & TD_MIRROR_EDGE_X) {
+ td->loc[0] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Y) {
+ td->loc[1] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Z) {
+ td->loc[2] = 0.0f;
+ }
+ }
+ }
+
+ TransDataMirror *tdm;
+ for (i = 0, tdm = tc->mirror.data; i < tc->mirror.data_len; i++, tdm++) {
+ tdm->loc_dst[0] = tdm->loc_src[0] * tdm->sign_x;
+ tdm->loc_dst[1] = tdm->loc_src[1] * tdm->sign_y;
+ tdm->loc_dst[2] = tdm->loc_src[2] * tdm->sign_z;
+ }
+ }
+ }
+}
+
+void recalcData_mesh(TransInfo *t)
+{
+ /* mirror modifier clipping? */
+ if (t->state != TRANS_CANCEL) {
+ /* apply clipping after so we never project past the clip plane [#25423] */
+ applyProject(t);
+ clipMirrorModifier(t);
+ }
+ if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
+ transform_apply_to_mirror(t);
+ }
+
+ if (t->mode == TFM_EDGE_SLIDE) {
+ projectEdgeSlideData(t, false);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ projectVertSlideData(t, false);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ EDBM_mesh_normals_update(em);
+ BKE_editmesh_looptri_calc(em);
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 5328bac7f79..337f7a83f9e 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -266,7 +266,7 @@ void createTransUVs(bContext *C, TransInfo *t)
*
* \{ */
-void flushTransUVs(TransInfo *t)
+static void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
@@ -314,4 +314,21 @@ void flushTransUVs(TransInfo *t)
}
}
+/* helper for recalcData() - for Image Editor transforms */
+void recalcData_uv(TransInfo *t)
+{
+ SpaceImage *sima = t->area->spacedata.first;
+
+ flushTransUVs(t);
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_re_solve();
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0);
+ }
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 2978c36b15f..1a38d01a81c 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -34,6 +34,9 @@
#include "BKE_report.h"
#include "ED_anim_api.h"
+#include "ED_markers.h"
+
+#include "RNA_access.h"
#include "transform.h"
#include "transform_convert.h"
@@ -256,4 +259,232 @@ void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
+/* helper for recalcData() - for NLA Editor transforms */
+void recalcData_nla(TransInfo *t)
+{
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
+ Scene *scene = t->scene;
+ double secf = FPS;
+ int i;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransDataNla *tdn = tc->custom.type.data;
+
+ /* For each strip we've got, perform some additional validation of the values
+ * that got set before using RNA to set the value (which does some special
+ * operations when setting these values to make sure that everything works ok).
+ */
+ for (i = 0; i < tc->data_len; i++, tdn++) {
+ NlaStrip *strip = tdn->strip;
+ PointerRNA strip_ptr;
+ short pExceeded, nExceeded, iter;
+ int delta_y1, delta_y2;
+
+ /* if this tdn has no handles, that means it is just a dummy that should be skipped */
+ if (tdn->handle == 0) {
+ continue;
+ }
+
+ /* set refresh tags for objects using this animation,
+ * BUT only if realtime updates are enabled
+ */
+ if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0) {
+ ANIM_id_update(CTX_data_main(t->context), tdn->id);
+ }
+
+ /* if canceling transform, just write the values without validating, then move on */
+ if (t->state == TRANS_CANCEL) {
+ /* clear the values by directly overwriting the originals, but also need to restore
+ * endpoints of neighboring transition-strips
+ */
+
+ /* start */
+ strip->start = tdn->h1[0];
+
+ if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) {
+ strip->prev->end = tdn->h1[0];
+ }
+
+ /* end */
+ strip->end = tdn->h2[0];
+
+ if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION)) {
+ strip->next->start = tdn->h2[0];
+ }
+
+ /* flush transforms to child strips (since this should be a meta) */
+ BKE_nlameta_flush_transforms(strip);
+
+ /* restore to original track (if needed) */
+ if (tdn->oldTrack != tdn->nlt) {
+ /* Just append to end of list for now,
+ * since strips get sorted in special_aftertrans_update(). */
+ BLI_remlink(&tdn->nlt->strips, strip);
+ BLI_addtail(&tdn->oldTrack->strips, strip);
+ }
+
+ continue;
+ }
+
+ /* firstly, check if the proposed transform locations would overlap with any neighboring strips
+ * (barring transitions) which are absolute barriers since they are not being moved
+ *
+ * this is done as a iterative procedure (done 5 times max for now)
+ */
+ for (iter = 0; iter < 5; iter++) {
+ pExceeded = ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) &&
+ (tdn->h1[0] < strip->prev->end));
+ nExceeded = ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) &&
+ (tdn->h2[0] > strip->next->start));
+
+ if ((pExceeded && nExceeded) || (iter == 4)) {
+ /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
+ * - Simply crop strip to fit within the bounds of the strips bounding it
+ * - If there were no neighbors, clear the transforms
+ * (make it default to the strip's current values).
+ */
+ if (strip->prev && strip->next) {
+ tdn->h1[0] = strip->prev->end;
+ tdn->h2[0] = strip->next->start;
+ }
+ else {
+ tdn->h1[0] = strip->start;
+ tdn->h2[0] = strip->end;
+ }
+ }
+ else if (nExceeded) {
+ /* move backwards */
+ float offset = tdn->h2[0] - strip->next->start;
+
+ tdn->h1[0] -= offset;
+ tdn->h2[0] -= offset;
+ }
+ else if (pExceeded) {
+ /* more forwards */
+ float offset = strip->prev->end - tdn->h1[0];
+
+ tdn->h1[0] += offset;
+ tdn->h2[0] += offset;
+ }
+ else { /* all is fine and well */
+ break;
+ }
+ }
+
+ /* handle auto-snapping
+ * NOTE: only do this when transform is still running, or we can't restore
+ */
+ if (t->state != TRANS_CANCEL) {
+ switch (snla->autosnap) {
+ case SACTSNAP_FRAME: /* snap to nearest frame */
+ case SACTSNAP_STEP: /* frame step - this is basically the same,
+ * since we don't have any remapping going on */
+ {
+ tdn->h1[0] = floorf(tdn->h1[0] + 0.5f);
+ tdn->h2[0] = floorf(tdn->h2[0] + 0.5f);
+ break;
+ }
+
+ case SACTSNAP_SECOND: /* snap to nearest second */
+ case SACTSNAP_TSTEP: /* second step - this is basically the same,
+ * since we don't have any remapping going on */
+ {
+ /* This case behaves differently from the rest, since lengths of strips
+ * may not be multiples of a second. If we just naively resize adjust
+ * the handles, things may not work correctly. Instead, we only snap
+ * the first handle, and move the other to fit.
+ *
+ * FIXME: we do run into problems here when user attempts to negatively
+ * scale the strip, as it then just compresses down and refuses
+ * to expand out the other end.
+ */
+ float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf);
+ float delta = h1_new - tdn->h1[0];
+
+ tdn->h1[0] = h1_new;
+ tdn->h2[0] += delta;
+ break;
+ }
+
+ case SACTSNAP_MARKER: /* snap to nearest marker */
+ {
+ tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
+ tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
+ break;
+ }
+ }
+ }
+
+ /* Use RNA to write the values to ensure that constraints on these are obeyed
+ * (e.g. for transition strips, the values are taken from the neighbors)
+ *
+ * NOTE: we write these twice to avoid truncation errors which can arise when
+ * moving the strips a large distance using numeric input [#33852]
+ */
+ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
+
+ RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
+ RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
+
+ RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
+ RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
+
+ /* flush transforms to child strips (since this should be a meta) */
+ BKE_nlameta_flush_transforms(strip);
+
+ /* Now, check if we need to try and move track:
+ * - we need to calculate both,
+ * as only one may have been altered by transform if only 1 handle moved.
+ */
+ delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
+ delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
+
+ if (delta_y1 || delta_y2) {
+ NlaTrack *track;
+ int delta = (delta_y2) ? delta_y2 : delta_y1;
+ int n;
+
+ /* Move in the requested direction,
+ * checking at each layer if there's space for strip to pass through,
+ * stopping on the last track available or that we're able to fit in.
+ */
+ if (delta > 0) {
+ for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
+ /* check if space in this track for the strip */
+ if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
+ /* move strip to this track */
+ BLI_remlink(&tdn->nlt->strips, strip);
+ BKE_nlatrack_add_strip(track, strip);
+
+ tdn->nlt = track;
+ tdn->trackIndex++;
+ }
+ else { /* can't move any further */
+ break;
+ }
+ }
+ }
+ else {
+ /* make delta 'positive' before using it, since we now know to go backwards */
+ delta = -delta;
+
+ for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
+ /* check if space in this track for the strip */
+ if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
+ /* move strip to this track */
+ BLI_remlink(&tdn->nlt->strips, strip);
+ BKE_nlatrack_add_strip(track, strip);
+
+ tdn->nlt = track;
+ tdn->trackIndex--;
+ }
+ else { /* can't move any further */
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index d783bfdf40e..d23a8f960c1 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -104,7 +104,7 @@ static bool is_node_parent_select(bNode *node)
return false;
}
-void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
+void createTransNodeData(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
TransData *td;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 8deba0f7ad0..1e33b9653f9 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -38,11 +38,15 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "DEG_depsgraph_query.h"
#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
@@ -96,7 +100,7 @@ static void freeTransObjectCustomData(TransInfo *t,
* Nearly all of the logic here is in the 'ED_object_data_xform_container_*' API.
* \{ */
-void trans_obdata_in_obmode_update_all(TransInfo *t)
+static void trans_obdata_in_obmode_update_all(TransInfo *t)
{
TransDataObject *tdo = t->custom.type.data;
if (tdo->xds == NULL) {
@@ -119,7 +123,7 @@ void trans_obdata_in_obmode_update_all(TransInfo *t)
*
* \{ */
-void trans_obchild_in_obmode_update_all(TransInfo *t)
+static void trans_obchild_in_obmode_update_all(TransInfo *t)
{
TransDataObject *tdo = t->custom.type.data;
if (tdo->xcs == NULL) {
@@ -762,3 +766,66 @@ void createTransTexspace(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Data object
+ *
+ * \{ */
+
+/* helper for recalcData() - for object transforms, typically in the 3D view */
+void recalcData_objects(TransInfo *t)
+{
+ bool motionpath_update = false;
+
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ Object *ob = td->ob;
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ /* if animtimer is running, and the object already has animation data,
+ * check if the auto-record feature means that we should record 'samples'
+ * (i.e. uneditable animation values)
+ */
+ /* TODO: autokeyframe calls need some setting to specify to add samples
+ * (FPoints) instead of keyframes? */
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+ animrecord_check_state(t, ob);
+ autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
+ }
+
+ motionpath_update |= motionpath_need_update_object(t->scene, ob);
+
+ /* sets recalc flags fully, instead of flushing existing ones
+ * otherwise proxies don't function correctly
+ */
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+
+ if (t->flag & T_TEXTURE) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ }
+
+ if (motionpath_update) {
+ /* Update motion paths once for all transformed objects. */
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ trans_obchild_in_obmode_update_all(t);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ trans_obdata_in_obmode_update_all(t);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index 4e1fc6ae1fa..5feaa70ba19 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -35,6 +35,9 @@
#include "ED_particle.h"
#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
@@ -193,7 +196,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t)
*
* \{ */
-void flushTransParticles(TransInfo *t)
+static void flushTransParticles(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
Scene *scene = t->scene;
@@ -245,3 +248,18 @@ void flushTransParticles(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Trasform Particles Data
+ *
+ * \{ */
+
+void recalcData_particles(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+ flushTransParticles(t);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
index 55dc36e9693..b439c9a1731 100644
--- a/source/blender/editors/transform/transform_convert_sculpt.c
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -29,6 +29,8 @@
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "ED_sculpt.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -100,3 +102,15 @@ void createTransSculpt(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Data object
+ *
+ * \{ */
+
+void recalcData_sculpt(TransInfo *t)
+{
+ ED_sculpt_update_modal_transform(t->context);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index deaf3689ceb..226f460de9a 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -635,7 +635,7 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s
}
}
-void flushTransSeq(TransInfo *t)
+static void flushTransSeq(TransInfo *t)
{
/* Editing null check already done */
ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep;
@@ -770,6 +770,31 @@ void flushTransSeq(TransInfo *t)
}
}
+/* helper for recalcData() - for sequencer transforms */
+void recalcData_sequencer(TransInfo *t)
+{
+ TransData *td;
+ int a;
+ Sequence *seq_prev = NULL;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
+ TransDataSeq *tdsq = (TransDataSeq *)td->extra;
+ Sequence *seq = tdsq->seq;
+
+ if (seq != seq_prev) {
+ BKE_sequence_invalidate_cache_composite(t->scene, seq);
+ }
+
+ seq_prev = seq;
+ }
+
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
+
+ flushTransSeq(t);
+}
+
int transform_convert_sequencer_get_snap_bound(TransInfo *t)
{
TransSeq *ts = TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 6704567a76b..0f00f5bc318 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -608,11 +608,11 @@ void cancelTransTracking(TransInfo *t)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Clip Editor Motion Tracking Transform Creation
+/** \name recalc Motion Tracking TransData
*
* \{ */
-void flushTransTracking(TransInfo *t)
+static void flushTransTracking(TransInfo *t)
{
TransData *td;
TransData2D *td2d;
@@ -689,4 +689,52 @@ void flushTransTracking(TransInfo *t)
}
}
+/* helper for recalcData() - for Movie Clip transforms */
+void recalcData_tracking(TransInfo *t)
+{
+ SpaceClip *sc = t->area->spacedata.first;
+
+ if (ED_space_clip_check_show_trackedit(sc)) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ MovieTrackingTrack *track;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ flushTransTracking(t);
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+
+ if (t->mode == TFM_TRANSLATION) {
+ if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
+ BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
+ }
+ if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
+ BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_POS);
+ }
+ }
+ else if (t->mode == TFM_RESIZE) {
+ if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
+ BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
+ }
+ if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
+ BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
+ }
+ }
+ else if (t->mode == TFM_ROTATION) {
+ if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
+ BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
+ }
+ }
+ }
+
+ track = track->next;
+ }
+
+ DEG_id_tag_update(&clip->id, 0);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 6de962a3ed1..beafbfab1ff 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -22,35 +22,15 @@
*/
#include <math.h>
-#include <string.h>
#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" /* for intptr_t support */
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_space_types.h"
-#include "DNA_view3d_types.h"
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_rand.h"
-#include "BLI_utildefines.h"
#include "PIL_time.h"
@@ -61,58 +41,25 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
-#include "BIK_api.h"
-
-#include "BKE_action.h"
-#include "BKE_anim_data.h"
-#include "BKE_armature.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_editmesh.h"
-#include "BKE_fcurve.h"
-#include "BKE_gpencil_geom.h"
-#include "BKE_lattice.h"
#include "BKE_layer.h"
-#include "BKE_lib_id.h"
#include "BKE_mask.h"
-#include "BKE_nla.h"
#include "BKE_paint.h"
-#include "BKE_scene.h"
-#include "BKE_sequencer.h"
-#include "BKE_tracking.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-#include "ED_anim_api.h"
-#include "ED_armature.h"
#include "ED_clip.h"
-#include "ED_curve.h" /* for curve_editnurbs */
-#include "ED_gpencil.h"
#include "ED_image.h"
-#include "ED_keyframing.h"
-#include "ED_markers.h"
-#include "ED_mesh.h"
#include "ED_object.h"
-#include "ED_particle.h"
#include "ED_screen.h"
-#include "ED_screen_types.h"
-#include "ED_sculpt.h"
#include "ED_space_api.h"
#include "ED_uvedit.h"
-#include "ED_view3d.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "RE_engine.h"
-
#include "UI_resources.h"
#include "UI_view2d.h"
#include "transform.h"
-#include "transform_convert.h"
#include "transform_mode.h"
#include "transform_snap.h"
@@ -131,1085 +78,6 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3])
/* ************************** GENERICS **************************** */
-static void clipMirrorModifier(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->obedit;
- ModifierData *md = ob->modifiers.first;
- float tolerance[3] = {0.0f, 0.0f, 0.0f};
- int axis = 0;
-
- for (; md; md = md->next) {
- if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
-
- if (mmd->flag & MOD_MIR_CLIPPING) {
- axis = 0;
- if (mmd->flag & MOD_MIR_AXIS_X) {
- axis |= 1;
- tolerance[0] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Y) {
- axis |= 2;
- tolerance[1] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Z) {
- axis |= 4;
- tolerance[2] = mmd->tolerance;
- }
- if (axis) {
- float mtx[4][4], imtx[4][4];
- int i;
-
- if (mmd->mirror_ob) {
- float obinv[4][4];
-
- invert_m4_m4(obinv, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obinv, ob->obmat);
- invert_m4_m4(imtx, mtx);
- }
-
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- int clip;
- float loc[3], iloc[3];
-
- if (td->loc == NULL) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- copy_v3_v3(loc, td->loc);
- copy_v3_v3(iloc, td->iloc);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, loc);
- mul_m4_v3(mtx, iloc);
- }
-
- clip = 0;
- if (axis & 1) {
- if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) {
- loc[0] = 0.0f;
- clip = 1;
- }
- }
-
- if (axis & 2) {
- if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) {
- loc[1] = 0.0f;
- clip = 1;
- }
- }
- if (axis & 4) {
- if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) {
- loc[2] = 0.0f;
- clip = 1;
- }
- }
- if (clip) {
- if (mmd->mirror_ob) {
- mul_m4_v3(imtx, loc);
- }
- copy_v3_v3(td->loc, loc);
- }
- }
- }
- }
- }
- }
- }
-}
-
-/* assumes obedit set to mesh object */
-static void transform_apply_to_mirror(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->mirror.use_mirror_any) {
- int i;
- TransData *td;
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
- if (td->flag & TD_MIRROR_EDGE_X) {
- td->loc[0] = 0.0f;
- }
- if (td->flag & TD_MIRROR_EDGE_Y) {
- td->loc[1] = 0.0f;
- }
- if (td->flag & TD_MIRROR_EDGE_Z) {
- td->loc[2] = 0.0f;
- }
- }
- }
-
- TransDataMirror *tdm;
- for (i = 0, tdm = tc->mirror.data; i < tc->mirror.data_len; i++, tdm++) {
- tdm->loc_dst[0] = tdm->loc_src[0] * tdm->sign_x;
- tdm->loc_dst[1] = tdm->loc_src[1] * tdm->sign_y;
- tdm->loc_dst[2] = tdm->loc_src[2] * tdm->sign_z;
- }
- }
- }
-}
-
-/* for the realtime animation recording feature, handle overlapping data */
-static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
-{
- ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
-
- /* sanity checks */
- if (ELEM(NULL, scene, id, sad)) {
- return;
- }
-
- /* check if we need a new strip if:
- * - if animtimer is running
- * - we're not only keying for available channels
- * - the option to add new actions for each round is not enabled
- */
- if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0 &&
- (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
- /* if playback has just looped around,
- * we need to add a new NLA track+strip to allow a clean pass to occur */
- if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
- AnimData *adt = BKE_animdata_from_id(id);
- const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
-
- /* perform push-down manually with some differences
- * NOTE: BKE_nla_action_pushdown() sync warning...
- */
- if ((adt->action) && !(adt->flag & ADT_NLA_EDIT_ON)) {
- float astart, aend;
-
- /* only push down if action is more than 1-2 frames long */
- calc_action_range(adt->action, &astart, &aend, 1);
- if (aend > astart + 2.0f) {
- NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
-
- /* clear reference to action now that we've pushed it onto the stack */
- id_us_min(&adt->action->id);
- adt->action = NULL;
-
- /* adjust blending + extend so that they will behave correctly */
- strip->extendmode = NLASTRIP_EXTEND_NOTHING;
- strip->flag &= ~(NLASTRIP_FLAG_AUTO_BLENDS | NLASTRIP_FLAG_SELECT |
- NLASTRIP_FLAG_ACTIVE);
-
- /* copy current "action blending" settings from adt to the strip,
- * as it was keyframed with these settings, so omitting them will
- * change the effect [T54766]
- */
- if (is_first == false) {
- strip->blendmode = adt->act_blendmode;
- strip->influence = adt->act_influence;
-
- if (adt->act_influence < 1.0f) {
- /* enable "user-controlled" influence (which will insert a default keyframe)
- * so that the influence doesn't get lost on the new update
- *
- * NOTE: An alternative way would have been to instead hack the influence
- * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
- * is disabled but auto-blending isn't being used. However, that approach
- * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
- * so it's better to just do it this way.
- */
- strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- BKE_nlastrip_validate_fcurves(strip);
- }
- }
-
- /* also, adjust the AnimData's action extend mode to be on
- * 'nothing' so that previous result still play
- */
- adt->act_extendmode = NLASTRIP_EXTEND_NOTHING;
- }
- }
- }
- }
-}
-
-static bool fcu_test_selected(FCurve *fcu)
-{
- BezTriple *bezt = fcu->bezt;
- uint i;
-
- if (bezt == NULL) { /* ignore baked */
- return 0;
- }
-
- for (i = 0; i < fcu->totvert; i++, bezt++) {
- if (BEZT_ISSEL_ANY(bezt)) {
- return 1;
- }
- }
-
- return 0;
-}
-
-/* helper for recalcData() - for Action Editor transforms */
-static void recalcData_actedit(TransInfo *t)
-{
- ViewLayer *view_layer = t->view_layer;
- SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
-
- bAnimContext ac = {NULL};
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* initialize relevant anim-context 'context' data from TransInfo data */
- /* NOTE: sync this with the code in ANIM_animdata_get_context() */
- ac.bmain = CTX_data_main(t->context);
- ac.scene = t->scene;
- ac.view_layer = t->view_layer;
- ac.obact = OBACT(view_layer);
- ac.area = t->area;
- ac.region = t->region;
- ac.sl = (t->area) ? t->area->spacedata.first : NULL;
- ac.spacetype = (t->area) ? t->area->spacetype : 0;
- ac.regiontype = (t->region) ? t->region->regiontype : 0;
-
- ANIM_animdata_context_getdata(&ac);
-
- /* perform flush */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- /* flush transform values back to actual coordinates */
- flushTransIntFrameActionData(t);
- }
-
- if (ac.datatype != ANIMCONT_MASK) {
- /* Get animdata blocks visible in editor,
- * assuming that these will be the ones where things changed. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* just tag these animdata-blocks to recalc, assuming that some data there changed
- * BUT only do this if realtime updates are enabled
- */
- if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* set refresh tags for objects using this animation */
- ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
- }
- }
-
- /* now free temp channels */
- ANIM_animdata_freelist(&anim_data);
- }
-}
-/* helper for recalcData() - for Graph Editor transforms */
-static void recalcData_graphedit(TransInfo *t)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
- ViewLayer *view_layer = t->view_layer;
-
- ListBase anim_data = {NULL, NULL};
- bAnimContext ac = {NULL};
- int filter;
-
- bAnimListElem *ale;
- int dosort = 0;
-
- /* initialize relevant anim-context 'context' data from TransInfo data */
- /* NOTE: sync this with the code in ANIM_animdata_get_context() */
- ac.bmain = CTX_data_main(t->context);
- ac.scene = t->scene;
- ac.view_layer = t->view_layer;
- ac.obact = OBACT(view_layer);
- ac.area = t->area;
- ac.region = t->region;
- ac.sl = (t->area) ? t->area->spacedata.first : NULL;
- ac.spacetype = (t->area) ? t->area->spacetype : 0;
- ac.regiontype = (t->region) ? t->region->regiontype : 0;
-
- ANIM_animdata_context_getdata(&ac);
-
- /* do the flush first */
- flushTransGraphData(t);
-
- /* get curves to check if a re-sort is needed */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* now test if there is a need to re-sort */
- for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* ignore FC-Curves without any selected verts */
- if (!fcu_test_selected(fcu)) {
- continue;
- }
-
- /* watch it: if the time is wrong: do not correct handles yet */
- if (test_time_fcurve(fcu)) {
- dosort++;
- }
- else {
- calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG);
- }
-
- /* set refresh tags for objects using this animation,
- * BUT only if realtime updates are enabled
- */
- if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0) {
- ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
- }
- }
-
- /* do resort and other updates? */
- if (dosort) {
- remake_graph_transdata(t, &anim_data);
- }
-
- /* now free temp channels */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* helper for recalcData() - for NLA Editor transforms */
-static void recalcData_nla(TransInfo *t)
-{
- SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
- Scene *scene = t->scene;
- double secf = FPS;
- int i;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- TransDataNla *tdn = tc->custom.type.data;
-
- /* For each strip we've got, perform some additional validation of the values
- * that got set before using RNA to set the value (which does some special
- * operations when setting these values to make sure that everything works ok).
- */
- for (i = 0; i < tc->data_len; i++, tdn++) {
- NlaStrip *strip = tdn->strip;
- PointerRNA strip_ptr;
- short pExceeded, nExceeded, iter;
- int delta_y1, delta_y2;
-
- /* if this tdn has no handles, that means it is just a dummy that should be skipped */
- if (tdn->handle == 0) {
- continue;
- }
-
- /* set refresh tags for objects using this animation,
- * BUT only if realtime updates are enabled
- */
- if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0) {
- ANIM_id_update(CTX_data_main(t->context), tdn->id);
- }
-
- /* if canceling transform, just write the values without validating, then move on */
- if (t->state == TRANS_CANCEL) {
- /* clear the values by directly overwriting the originals, but also need to restore
- * endpoints of neighboring transition-strips
- */
-
- /* start */
- strip->start = tdn->h1[0];
-
- if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) {
- strip->prev->end = tdn->h1[0];
- }
-
- /* end */
- strip->end = tdn->h2[0];
-
- if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION)) {
- strip->next->start = tdn->h2[0];
- }
-
- /* flush transforms to child strips (since this should be a meta) */
- BKE_nlameta_flush_transforms(strip);
-
- /* restore to original track (if needed) */
- if (tdn->oldTrack != tdn->nlt) {
- /* Just append to end of list for now,
- * since strips get sorted in special_aftertrans_update(). */
- BLI_remlink(&tdn->nlt->strips, strip);
- BLI_addtail(&tdn->oldTrack->strips, strip);
- }
-
- continue;
- }
-
- /* firstly, check if the proposed transform locations would overlap with any neighboring strips
- * (barring transitions) which are absolute barriers since they are not being moved
- *
- * this is done as a iterative procedure (done 5 times max for now)
- */
- for (iter = 0; iter < 5; iter++) {
- pExceeded = ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) &&
- (tdn->h1[0] < strip->prev->end));
- nExceeded = ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) &&
- (tdn->h2[0] > strip->next->start));
-
- if ((pExceeded && nExceeded) || (iter == 4)) {
- /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
- * - Simply crop strip to fit within the bounds of the strips bounding it
- * - If there were no neighbors, clear the transforms
- * (make it default to the strip's current values).
- */
- if (strip->prev && strip->next) {
- tdn->h1[0] = strip->prev->end;
- tdn->h2[0] = strip->next->start;
- }
- else {
- tdn->h1[0] = strip->start;
- tdn->h2[0] = strip->end;
- }
- }
- else if (nExceeded) {
- /* move backwards */
- float offset = tdn->h2[0] - strip->next->start;
-
- tdn->h1[0] -= offset;
- tdn->h2[0] -= offset;
- }
- else if (pExceeded) {
- /* more forwards */
- float offset = strip->prev->end - tdn->h1[0];
-
- tdn->h1[0] += offset;
- tdn->h2[0] += offset;
- }
- else { /* all is fine and well */
- break;
- }
- }
-
- /* handle auto-snapping
- * NOTE: only do this when transform is still running, or we can't restore
- */
- if (t->state != TRANS_CANCEL) {
- switch (snla->autosnap) {
- case SACTSNAP_FRAME: /* snap to nearest frame */
- case SACTSNAP_STEP: /* frame step - this is basically the same,
- * since we don't have any remapping going on */
- {
- tdn->h1[0] = floorf(tdn->h1[0] + 0.5f);
- tdn->h2[0] = floorf(tdn->h2[0] + 0.5f);
- break;
- }
-
- case SACTSNAP_SECOND: /* snap to nearest second */
- case SACTSNAP_TSTEP: /* second step - this is basically the same,
- * since we don't have any remapping going on */
- {
- /* This case behaves differently from the rest, since lengths of strips
- * may not be multiples of a second. If we just naively resize adjust
- * the handles, things may not work correctly. Instead, we only snap
- * the first handle, and move the other to fit.
- *
- * FIXME: we do run into problems here when user attempts to negatively
- * scale the strip, as it then just compresses down and refuses
- * to expand out the other end.
- */
- float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf);
- float delta = h1_new - tdn->h1[0];
-
- tdn->h1[0] = h1_new;
- tdn->h2[0] += delta;
- break;
- }
-
- case SACTSNAP_MARKER: /* snap to nearest marker */
- {
- tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
- tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
- break;
- }
- }
- }
-
- /* Use RNA to write the values to ensure that constraints on these are obeyed
- * (e.g. for transition strips, the values are taken from the neighbors)
- *
- * NOTE: we write these twice to avoid truncation errors which can arise when
- * moving the strips a large distance using numeric input [#33852]
- */
- RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
-
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
-
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
-
- /* flush transforms to child strips (since this should be a meta) */
- BKE_nlameta_flush_transforms(strip);
-
- /* Now, check if we need to try and move track:
- * - we need to calculate both,
- * as only one may have been altered by transform if only 1 handle moved.
- */
- delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
- delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
-
- if (delta_y1 || delta_y2) {
- NlaTrack *track;
- int delta = (delta_y2) ? delta_y2 : delta_y1;
- int n;
-
- /* Move in the requested direction,
- * checking at each layer if there's space for strip to pass through,
- * stopping on the last track available or that we're able to fit in.
- */
- if (delta > 0) {
- for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
- /* check if space in this track for the strip */
- if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
- /* move strip to this track */
- BLI_remlink(&tdn->nlt->strips, strip);
- BKE_nlatrack_add_strip(track, strip);
-
- tdn->nlt = track;
- tdn->trackIndex++;
- }
- else { /* can't move any further */
- break;
- }
- }
- }
- else {
- /* make delta 'positive' before using it, since we now know to go backwards */
- delta = -delta;
-
- for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
- /* check if space in this track for the strip */
- if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
- /* move strip to this track */
- BLI_remlink(&tdn->nlt->strips, strip);
- BKE_nlatrack_add_strip(track, strip);
-
- tdn->nlt = track;
- tdn->trackIndex--;
- }
- else { /* can't move any further */
- break;
- }
- }
- }
- }
- }
-}
-
-static void recalcData_mask_common(TransInfo *t)
-{
- Mask *mask = CTX_data_edit_mask(t->context);
-
- flushTransMasking(t);
-
- DEG_id_tag_update(&mask->id, 0);
-}
-
-/* helper for recalcData() - for Image Editor transforms */
-static void recalcData_image(TransInfo *t)
-{
- if (t->options & CTX_MASK) {
- recalcData_mask_common(t);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- flushTransPaintCurve(t);
- }
- else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
- SpaceImage *sima = t->area->spacedata.first;
-
- flushTransUVs(t);
- if (sima->flag & SI_LIVE_UNWRAP) {
- ED_uvedit_live_unwrap_re_solve();
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len) {
- DEG_id_tag_update(tc->obedit->data, 0);
- }
- }
- }
-}
-
-/* helper for recalcData() - for Movie Clip transforms */
-static void recalcData_spaceclip(TransInfo *t)
-{
- SpaceClip *sc = t->area->spacedata.first;
-
- if (ED_space_clip_check_show_trackedit(sc)) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- flushTransTracking(t);
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- if (t->mode == TFM_TRANSLATION) {
- if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
- }
- if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
- BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_POS);
- }
- }
- else if (t->mode == TFM_RESIZE) {
- if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
- }
- if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
- BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
- }
- }
- else if (t->mode == TFM_ROTATION) {
- if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
- }
- }
- }
-
- track = track->next;
- }
-
- DEG_id_tag_update(&clip->id, 0);
- }
- else if (t->options & CTX_MASK) {
- recalcData_mask_common(t);
- }
-}
-
-/* helper for recalcData() - for object transforms, typically in the 3D view */
-static void recalcData_objects(TransInfo *t)
-{
- Base *base = t->view_layer->basact;
-
- if (t->obedit_type != -1) {
- if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
-
- if (t->state != TRANS_CANCEL) {
- clipMirrorModifier(t);
- applyProject(t);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Curve *cu = tc->obedit->data;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- Nurb *nu = nurbs->first;
-
- DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
-
- if (t->state == TRANS_CANCEL) {
- while (nu) {
- /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
- BKE_nurb_handles_calc(nu);
- nu = nu->next;
- }
- }
- else {
- /* Normal updating */
- while (nu) {
- BKE_nurb_test_2d(nu);
- BKE_nurb_handles_calc(nu);
- nu = nu->next;
- }
- }
- }
- }
- else if (t->obedit_type == OB_LATTICE) {
-
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Lattice *la = tc->obedit->data;
- DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
- if (la->editlatt->latt->flag & LT_OUTSIDE) {
- outside_lattice(la->editlatt->latt);
- }
- }
- }
- else if (t->obedit_type == OB_MESH) {
- /* mirror modifier clipping? */
- if (t->state != TRANS_CANCEL) {
- /* apply clipping after so we never project past the clip plane [#25423] */
- applyProject(t);
- clipMirrorModifier(t);
- }
- if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
- transform_apply_to_mirror(t);
- }
-
- if (t->mode == TFM_EDGE_SLIDE) {
- projectEdgeSlideData(t, false);
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- projectVertSlideData(t, false);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
- }
- }
- else if (t->obedit_type == OB_ARMATURE) { /* no recalc flag, does pose */
-
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- bArmature *arm = tc->obedit->data;
- ListBase *edbo = arm->edbo;
- EditBone *ebo, *ebo_parent;
- TransData *td = tc->data;
- int i;
-
- /* Ensure all bones are correctly adjusted */
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
-
- if (ebo_parent) {
- /* If this bone has a parent tip that has been moved */
- if (ebo_parent->flag & BONE_TIPSEL) {
- copy_v3_v3(ebo->head, ebo_parent->tail);
- if (t->mode == TFM_BONE_ENVELOPE) {
- ebo->rad_head = ebo_parent->rad_tail;
- }
- }
- /* If this bone has a parent tip that has NOT been moved */
- else {
- copy_v3_v3(ebo_parent->tail, ebo->head);
- if (t->mode == TFM_BONE_ENVELOPE) {
- ebo_parent->rad_tail = ebo->rad_head;
- }
- }
- }
-
- /* on extrude bones, oldlength==0.0f, so we scale radius of points */
- ebo->length = len_v3v3(ebo->head, ebo->tail);
- if (ebo->oldlength == 0.0f) {
- ebo->rad_head = 0.25f * ebo->length;
- ebo->rad_tail = 0.10f * ebo->length;
- ebo->dist = 0.25f * ebo->length;
- if (ebo->parent) {
- if (ebo->rad_head > ebo->parent->rad_tail) {
- ebo->rad_head = ebo->parent->rad_tail;
- }
- }
- }
- else if (t->mode != TFM_BONE_ENVELOPE) {
- /* if bones change length, lets do that for the deform distance as well */
- ebo->dist *= ebo->length / ebo->oldlength;
- ebo->rad_head *= ebo->length / ebo->oldlength;
- ebo->rad_tail *= ebo->length / ebo->oldlength;
- ebo->oldlength = ebo->length;
-
- if (ebo_parent) {
- ebo_parent->rad_tail = ebo->rad_head;
- }
- }
- }
-
- if (!ELEM(
- t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
- /* fix roll */
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->extra) {
- float vec[3], up_axis[3];
- float qrot[4];
- float roll;
-
- ebo = td->extra;
-
- if (t->state == TRANS_CANCEL) {
- /* restore roll */
- ebo->roll = td->ival;
- }
- else {
- copy_v3_v3(up_axis, td->axismtx[2]);
-
- sub_v3_v3v3(vec, ebo->tail, ebo->head);
- normalize_v3(vec);
- rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
- mul_qt_v3(qrot, up_axis);
-
- /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
- roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
- ebo->roll = angle_compat_rad(roll, td->ival);
- }
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- if (t->state != TRANS_CANCEL) {
- ED_armature_edit_transform_mirror_update(tc->obedit);
- }
- else {
- restoreBones(tc);
- }
- }
-
- /* Tag for redraw/invalidate overlay cache. */
- DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
- }
- }
- else {
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len) {
- DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
- }
- }
- }
- }
- else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
- /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
- * in pose mode (to use bone orientation matrix),
- * in that case we have to do mirroring as well. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->poseobj;
- bArmature *arm = ob->data;
- if (ob->mode == OB_MODE_EDIT) {
- if (arm->flag & ARM_MIRROR_EDIT) {
- if (t->state != TRANS_CANCEL) {
- ED_armature_edit_transform_mirror_update(ob);
- }
- else {
- restoreBones(tc);
- }
- }
- }
- else if (ob->mode == OB_MODE_POSE) {
- /* actually support TFM_BONESIZE in posemode as well */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- bPose *pose = ob->pose;
- if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) {
- pose_transform_mirror_update(t, tc, ob);
- }
- }
- }
- }
- else if (t->flag & T_POSE) {
- GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->poseobj;
- bPose *pose = ob->pose;
-
- if (pose->flag & POSE_MIRROR_EDIT) {
- if (t->state != TRANS_CANCEL) {
- pose_transform_mirror_update(t, tc, ob);
- }
- else {
- restoreMirrorPoseBones(tc);
- }
- }
-
- /* if animtimer is running, and the object already has animation data,
- * check if the auto-record feature means that we should record 'samples'
- * (i.e. un-editable animation values)
- *
- * context is needed for keying set poll() functions.
- */
-
- /* TODO: autokeyframe calls need some setting to specify to add samples
- * (FPoints) instead of keyframes? */
- if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
- int targetless_ik =
- (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
-
- animrecord_check_state(t->scene, &ob->id, t->animtimer);
- autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
- }
-
- if (motionpath_need_update_pose(t->scene, ob)) {
- BLI_gset_insert(motionpath_updates, ob);
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- /* Update motion paths once for all transformed bones in an object. */
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, motionpath_updates) {
- Object *ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
- }
- BLI_gset_free(motionpath_updates, NULL);
- }
- else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->depsgraph, t->scene, base->object)) {
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
- flushTransParticles(t);
- }
- else {
- bool motionpath_update = false;
-
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
-
- for (int i = 0; i < tc->data_len; i++, td++) {
- Object *ob = td->ob;
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- /* if animtimer is running, and the object already has animation data,
- * check if the auto-record feature means that we should record 'samples'
- * (i.e. uneditable animation values)
- */
- /* TODO: autokeyframe calls need some setting to specify to add samples
- * (FPoints) instead of keyframes? */
- if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t->scene, &ob->id, t->animtimer);
- autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
- }
-
- motionpath_update |= motionpath_need_update_object(t->scene, ob);
-
- /* sets recalc flags fully, instead of flushing existing ones
- * otherwise proxies don't function correctly
- */
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
-
- if (t->flag & T_TEXTURE) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
- }
-
- if (motionpath_update) {
- /* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
- }
-
- if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
- trans_obchild_in_obmode_update_all(t);
- }
-
- if (t->options & CTX_OBMODE_XFORM_OBDATA) {
- trans_obdata_in_obmode_update_all(t);
- }
- }
-}
-
-static void recalcData_cursor(TransInfo *t)
-{
- DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-/* helper for recalcData() - for sequencer transforms */
-static void recalcData_sequencer(TransInfo *t)
-{
- TransData *td;
- int a;
- Sequence *seq_prev = NULL;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
- TransDataSeq *tdsq = (TransDataSeq *)td->extra;
- Sequence *seq = tdsq->seq;
-
- if (seq != seq_prev) {
- BKE_sequence_invalidate_cache_composite(t->scene, seq);
- }
-
- seq_prev = seq;
- }
-
- DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
-
- flushTransSeq(t);
-}
-
-/* force recalculation of triangles during transformation */
-static void recalcData_gpencil_strokes(TransInfo *t)
-{
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- GHash *strokes = BLI_ghash_ptr_new(__func__);
-
- TransData *td = tc->data;
- for (int i = 0; i < tc->data_len; i++, td++) {
- bGPDstroke *gps = td->extra;
-
- if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) {
- BLI_ghash_insert(strokes, gps, gps);
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
- }
- }
- BLI_ghash_free(strokes, NULL, NULL);
-}
-
-static void recalcData_sculpt(TransInfo *t)
-{
- ED_sculpt_update_modal_transform(t->context);
-}
-
-/* called for updating while transform acts, once per redraw */
-void recalcData(TransInfo *t)
-{
- /* if tests must match createTransData for correct updates */
- if (t->options & CTX_CURSOR) {
- recalcData_cursor(t);
- }
- else if (t->options & CTX_TEXTURE) {
- recalcData_objects(t);
- }
- else if (t->options & CTX_EDGE) {
- recalcData_objects(t);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- flushTransPaintCurve(t);
- }
- else if (t->options & CTX_GPENCIL_STROKES) {
- recalcData_gpencil_strokes(t);
- }
- else if (t->options & CTX_SCULPT) {
- recalcData_sculpt(t);
- }
- else if (t->spacetype == SPACE_IMAGE) {
- recalcData_image(t);
- }
- else if (t->spacetype == SPACE_ACTION) {
- recalcData_actedit(t);
- }
- else if (t->spacetype == SPACE_NLA) {
- recalcData_nla(t);
- }
- else if (t->spacetype == SPACE_SEQ) {
- recalcData_sequencer(t);
- }
- else if (t->spacetype == SPACE_GRAPH) {
- recalcData_graphedit(t);
- }
- else if (t->spacetype == SPACE_NODE) {
- flushTransNodes(t);
- }
- else if (t->spacetype == SPACE_CLIP) {
- recalcData_spaceclip(t);
- }
- else {
- recalcData_objects(t);
- }
-}
-
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
float v1[3], v2[3], v3[3];