diff options
Diffstat (limited to 'source')
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]; |