diff options
Diffstat (limited to 'source/blender/editors/transform')
52 files changed, 1849 insertions, 1135 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 68c4f4e76ca..6984dcb18d4 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRC transform_convert_mesh_edge.c transform_convert_mesh_skin.c transform_convert_mesh_uv.c + transform_convert_mesh_vert_cdata.c transform_convert_nla.c transform_convert_node.c transform_convert_object.c diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 960d9a25ca7..8dcbf07b776 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -525,7 +525,8 @@ static void viewRedrawPost(bContext *C, TransInfo *t) UVCALC_TRANSFORM_CORRECT_SLIDE : UVCALC_TRANSFORM_CORRECT; - if ((t->data_type == TC_MESH_VERTS) && (t->settings->uvcalc_flag & uvcalc_correct_flag)) { + if ((t->data_type == &TransConvertType_Mesh) && + (t->settings->uvcalc_flag & uvcalc_correct_flag)) { WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } @@ -847,7 +848,7 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type) return false; } - if (t->data_type == TC_SEQ_IMAGE_DATA) { + if (t->data_type == &TransConvertType_SequencerImage) { /* Setup the 2d msg string so it writes out the transform space. */ msg_2d = msg_3d; @@ -1327,7 +1328,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } - if (t->redraw && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (t->redraw && !ISMOUSE_MOTION(event->type)) { WM_window_status_area_tag_redraw(CTX_wm_window(t->context)); } @@ -1577,7 +1578,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (transformModeUseSnap(t)) { if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) { /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */ - char *snap_flag_ptr; + short *snap_flag_ptr; wmMsgParams_RNA msg_key_params = {{0}}; RNA_pointer_create(&t->scene->id, &RNA_ToolSettings, ts, &msg_key_params.ptr); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index a35942aedec..fc59787e1ec 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -38,6 +38,7 @@ struct ReportList; struct Scene; struct ScrArea; struct SnapObjectContext; +struct TransConvertTypeInfo; struct TransDataContainer; struct TransInfo; struct TransSnap; @@ -204,36 +205,6 @@ typedef enum { HLP_TRACKBALL = 6, } eTHelpline; -typedef enum { - TC_NONE = 0, - TC_ACTION_DATA, - TC_POSE, - TC_ARMATURE_VERTS, - TC_CURSOR_IMAGE, - TC_CURSOR_SEQUENCER, - 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_SKIN, - 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_SEQ_IMAGE_DATA, - TC_TRACKING_DATA, -} eTConvertType; - /** \} */ /* -------------------------------------------------------------------- */ @@ -306,9 +277,9 @@ typedef struct TransSnap { eSnapTargetSelect target_select; bool align; bool project; - bool snap_self; bool peel; bool use_backface_culling; + short face_nearest_steps; eTSnap status; /* Snapped Element Type (currently for objects only). */ eSnapMode snapElem; @@ -463,6 +434,8 @@ typedef struct TransDataContainer { int data_len; /** Total number of transformed data_mirror. */ int data_mirror_len; + /** Total number of transformed gp-frames. */ + int data_gpf_len; struct Object *obedit; @@ -516,7 +489,7 @@ typedef struct TransInfo { int data_len_all; /** TODO: It should be a member of #TransDataContainer. */ - eTConvertType data_type; + struct TransConvertTypeInfo *data_type; /** Current context/options for transform. */ eTContext options; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 0bb00032561..658901a6991 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -402,7 +402,7 @@ static void applyAxisConstraintVec(const TransInfo *t, if (activeSnap(t)) { if (validSnap(t)) { is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0; - is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0; + is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE_RAYCAST) != 0; is_snap_to_point = !is_snap_to_edge && !is_snap_to_face; } else if (t->tsnap.snapElem & SCE_SNAP_MODE_GRID) { diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index d9b971c5478..d1c2af75274 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -479,132 +479,6 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr /** \name UV Coordinates * \{ */ -/** - * Find the correction for the scaling factor when "Constrain to Bounds" is active. - * \param numerator: How far the UV boundary (unit square) is from the origin of the scale. - * \param denominator: How far the AABB is from the origin of the scale. - * \param scale: Scale parameter to update. - */ -static void constrain_scale_to_boundary(const float numerator, - const float denominator, - float *scale) -{ - if (denominator == 0.0f) { - /* The origin of the scale is on the edge of the boundary. */ - if (numerator < 0.0f) { - /* Negative scale will wrap around and put us outside the boundary. */ - *scale = 0.0f; /* Hold at the boundary instead. */ - } - return; /* Nothing else we can do without more info. */ - } - - const float correction = numerator / denominator; - if (correction < 0.0f || !isfinite(correction)) { - /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */ - return; - } - - if (denominator < 0.0f) { - /* Scale origin is outside boundary, only make scale bigger. */ - if (*scale < correction) { - *scale = correction; - } - return; - } - - /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */ - if (*scale > correction) { - *scale = correction; - } -} - -bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) -{ - bool clipx = true, clipy = true; - float min[2], max[2]; - - /* Check if the current image in UV editor is a tiled image or not. */ - const SpaceImage *sima = t->area->spacedata.first; - const Image *image = sima->image; - const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); - /* Stores the coordinates of the closest UDIM tile. - * Also acts as an offset to the tile from the origin of UV space. */ - float base_offset[2] = {0.0f, 0.0f}; - - /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ - if (is_tiled_image) { - int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); - if (nearest_tile_index != -1) { - nearest_tile_index -= 1001; - /* Getting coordinates of nearest tile from the tile index. */ - base_offset[0] = nearest_tile_index % 10; - base_offset[1] = nearest_tile_index / 10; - } - } - - min[0] = min[1] = FLT_MAX; - max[0] = max[1] = FLT_MIN; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - - TransData *td; - int a; - - for (a = 0, td = tc->data; a < tc->data_len; a++, td++) { - minmax_v2v2_v2(min, max, td->loc); - } - } - - if (resize) { - /* Assume no change is required. */ - float scalex = 1.0f; - float scaley = 1.0f; - - /* Update U against the left border. */ - constrain_scale_to_boundary( - t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex); - /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */ - constrain_scale_to_boundary(base_offset[0] + t->aspect[0] - t->center_global[0], - max[0] - t->center_global[0], - &scalex); - - /* Do the same for the V co-ordinate, which is called `y`. */ - constrain_scale_to_boundary( - t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley); - constrain_scale_to_boundary(base_offset[1] + t->aspect[1] - t->center_global[1], - max[1] - t->center_global[1], - &scaley); - - clipx = (scalex != 1.0f); - clipy = (scaley != 1.0f); - vec[0] *= scalex; - vec[1] *= scaley; - } - else { - if (min[0] < base_offset[0]) { - vec[0] += base_offset[0] - min[0]; - } - else if (max[0] > base_offset[0] + t->aspect[0]) { - vec[0] -= max[0] - base_offset[0] - t->aspect[0]; - } - else { - clipx = 0; - } - - if (min[1] < base_offset[1]) { - vec[1] += base_offset[1] - min[1]; - } - else if (max[1] > base_offset[1] + t->aspect[1]) { - vec[1] -= max[1] - base_offset[1] - t->aspect[1]; - } - else { - clipy = 0; - } - } - - return (clipx || clipy); -} - void clipUVData(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -769,7 +643,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand } else { /* Delete Keyframe */ - delete_fcurve_key(fcu, i, 0); + BKE_fcurve_delete_key(fcu, i); } /* Update count of how many we've deleted @@ -779,7 +653,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand } else { /* Always delete - Unselected keys don't matter */ - delete_fcurve_key(fcu, i, 0); + BKE_fcurve_delete_key(fcu, i); } /* Stop the RK search... we've found our match now */ @@ -902,62 +776,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t) return; } - BLI_assert(CTX_data_main(t->context) == CTX_data_main(C)); - switch (t->data_type) { - case TC_ACTION_DATA: - special_aftertrans_update__actedit(C, t); - break; - case TC_POSE: - special_aftertrans_update__pose(C, t); - break; - case TC_GRAPH_EDIT_DATA: - special_aftertrans_update__graph(C, t); - break; - case TC_MASKING_DATA: - special_aftertrans_update__mask(C, t); - break; - case TC_MESH_VERTS: - case TC_MESH_EDGES: - special_aftertrans_update__mesh(C, t); - break; - case TC_NLA_DATA: - special_aftertrans_update__nla(C, t); - break; - case TC_NODE_DATA: - special_aftertrans_update__node(C, t); - break; - case TC_OBJECT: - special_aftertrans_update__object(C, t); - break; - case TC_SCULPT: - special_aftertrans_update__sculpt(C, t); - break; - case TC_SEQ_DATA: - special_aftertrans_update__sequencer(C, t); - break; - case TC_SEQ_IMAGE_DATA: - special_aftertrans_update__sequencer_image(C, t); - break; - case TC_TRACKING_DATA: - special_aftertrans_update__movieclip(C, t); - break; - case TC_ARMATURE_VERTS: - case TC_CURSOR_IMAGE: - case TC_CURSOR_SEQUENCER: - case TC_CURSOR_VIEW3D: - case TC_CURVE_VERTS: - case TC_GPENCIL: - case TC_LATTICE_VERTS: - case TC_MBALL_VERTS: - case TC_MESH_UV: - case TC_MESH_SKIN: - case TC_OBJECT_TEXSPACE: - case TC_PAINT_CURVE_VERTS: - case TC_PARTICLE_VERTS: - case TC_NONE: - default: - break; + if (!t->data_type || !t->data_type->special_aftertrans_update) { + return; } + + BLI_assert(CTX_data_main(t->context) == CTX_data_main(C)); + t->data_type->special_aftertrans_update(C, t); } int special_transform_moving(TransInfo *t) @@ -1018,54 +842,44 @@ static int countAndCleanTransDataContainer(TransInfo *t) static void init_proportional_edit(TransInfo *t) { - eTConvertType convert_type = t->data_type; - switch (convert_type) { - case TC_ACTION_DATA: - case TC_CURVE_VERTS: - case TC_GRAPH_EDIT_DATA: - case TC_GPENCIL: - case TC_LATTICE_VERTS: - case TC_MASKING_DATA: - case TC_MBALL_VERTS: - case TC_MESH_VERTS: - case TC_MESH_EDGES: - case TC_MESH_SKIN: - case TC_MESH_UV: - case TC_NODE_DATA: - case TC_OBJECT: - case TC_PARTICLE_VERTS: - break; - case TC_POSE: /* Disable PET, its not usable in pose mode yet T32444. */ - case TC_ARMATURE_VERTS: - case TC_CURSOR_IMAGE: - case TC_CURSOR_SEQUENCER: - case TC_CURSOR_VIEW3D: - case TC_NLA_DATA: - case TC_OBJECT_TEXSPACE: - case TC_PAINT_CURVE_VERTS: - case TC_SCULPT: - case TC_SEQ_DATA: - case TC_SEQ_IMAGE_DATA: - case TC_TRACKING_DATA: - case TC_NONE: - default: - t->options |= CTX_NO_PET; - t->flag &= ~T_PROP_EDIT_ALL; - return; + /* NOTE: PET is not usable in pose mode yet T32444. */ + if (!ELEM(t->data_type, + &TransConvertType_Action, + &TransConvertType_Curve, + &TransConvertType_Graph, + &TransConvertType_GPencil, + &TransConvertType_Lattice, + &TransConvertType_Mask, + &TransConvertType_MBall, + &TransConvertType_Mesh, + &TransConvertType_MeshEdge, + &TransConvertType_MeshSkin, + &TransConvertType_MeshUV, + &TransConvertType_MeshVertCData, + &TransConvertType_Node, + &TransConvertType_Object, + &TransConvertType_Particle)) { + /* Disable PET */ + t->options |= CTX_NO_PET; + t->flag &= ~T_PROP_EDIT_ALL; + return; } if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - if (convert_type == TC_OBJECT) { + if (t->data_type == &TransConvertType_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)) { + if (ELEM(t->data_type, &TransConvertType_Action, &TransConvertType_Graph)) { /* Distance has already been set. */ } - else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN)) { + else if (ELEM(t->data_type, + &TransConvertType_Mesh, + &TransConvertType_MeshSkin, + &TransConvertType_MeshVertCData)) { if (t->flag & T_PROP_CONNECTED) { /* Already calculated by transform_convert_mesh_connectivity_distance. */ } @@ -1073,10 +887,10 @@ static void init_proportional_edit(TransInfo *t) set_prop_dist(t, false); } } - else if (convert_type == TC_MESH_UV && t->flag & T_PROP_CONNECTED) { + else if (t->data_type == &TransConvertType_MeshUV && t->flag & T_PROP_CONNECTED) { /* Already calculated by uv_set_connectivity_distance. */ } - else if (convert_type == TC_CURVE_VERTS) { + else if (t->data_type == &TransConvertType_Curve) { BLI_assert(t->obedit_type == OB_CURVES_LEGACY); set_prop_dist(t, false); } @@ -1099,44 +913,26 @@ static void init_TransDataContainers(TransInfo *t, Object **objects, uint objects_len) { - switch (t->data_type) { - case TC_POSE: - case TC_ARMATURE_VERTS: - case TC_CURVE_VERTS: - case TC_GPENCIL: - case TC_LATTICE_VERTS: - case TC_MBALL_VERTS: - case TC_MESH_VERTS: - case TC_MESH_EDGES: - case TC_MESH_SKIN: - case TC_MESH_UV: - break; - case TC_ACTION_DATA: - case TC_GRAPH_EDIT_DATA: - case TC_CURSOR_IMAGE: - case TC_CURSOR_SEQUENCER: - case TC_CURSOR_VIEW3D: - case TC_MASKING_DATA: - case TC_NLA_DATA: - case TC_NODE_DATA: - case TC_OBJECT: - case TC_OBJECT_TEXSPACE: - case TC_PAINT_CURVE_VERTS: - case TC_PARTICLE_VERTS: - case TC_SCULPT: - case TC_SEQ_DATA: - case TC_SEQ_IMAGE_DATA: - case TC_TRACKING_DATA: - case TC_NONE: - default: - /* Does not support Multi object editing. */ - return; + if (!ELEM(t->data_type, + &TransConvertType_Pose, + &TransConvertType_EditArmature, + &TransConvertType_Curve, + &TransConvertType_GPencil, + &TransConvertType_Lattice, + &TransConvertType_MBall, + &TransConvertType_Mesh, + &TransConvertType_MeshEdge, + &TransConvertType_MeshSkin, + &TransConvertType_MeshUV, + &TransConvertType_MeshVertCData)) { + /* Does not support Multi object editing. */ + return; } const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT; const short object_type = obact ? obact->type : -1; - if ((object_mode & OB_MODE_EDIT) || (t->data_type == TC_GPENCIL) || + if ((object_mode & OB_MODE_EDIT) || (t->data_type == &TransConvertType_GPencil) || ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE))) { if (t->data_container) { MEM_freeN(t->data_container); @@ -1178,7 +974,7 @@ static void init_TransDataContainers(TransInfo *t, tc->poseobj = objects[i]; tc->use_local_mat = true; } - else if (t->data_type == TC_GPENCIL) { + else if (t->data_type == &TransConvertType_GPencil) { tc->use_local_mat = true; } @@ -1201,173 +997,131 @@ static void init_TransDataContainers(TransInfo *t, } } -static eTFlag flags_from_data_type(eTConvertType data_type) -{ - switch (data_type) { - case TC_ACTION_DATA: - case TC_GRAPH_EDIT_DATA: - case TC_MASKING_DATA: - case TC_NLA_DATA: - case TC_NODE_DATA: - case TC_PAINT_CURVE_VERTS: - case TC_SEQ_DATA: - case TC_SEQ_IMAGE_DATA: - case TC_TRACKING_DATA: - return T_POINTS | T_2D_EDIT; - case TC_ARMATURE_VERTS: - case TC_CURVE_VERTS: - case TC_GPENCIL: - case TC_LATTICE_VERTS: - case TC_MBALL_VERTS: - case TC_MESH_VERTS: - case TC_MESH_SKIN: - return T_EDIT | T_POINTS; - case TC_MESH_EDGES: - return T_EDIT; - case TC_MESH_UV: - return T_EDIT | T_POINTS | T_2D_EDIT; - case TC_CURSOR_IMAGE: - case TC_CURSOR_SEQUENCER: - return T_2D_EDIT; - case TC_PARTICLE_VERTS: - return T_POINTS; - case TC_POSE: - case TC_CURSOR_VIEW3D: - case TC_OBJECT: - case TC_OBJECT_TEXSPACE: - case TC_SCULPT: - case TC_NONE: - default: - break; - } - return 0; -} - -static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armature) +static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj_armature) { ViewLayer *view_layer = t->view_layer; Object *ob = OBACT(view_layer); - eTConvertType convert_type = TC_NONE; /* if tests must match recalcData for correct updates */ if (t->options & CTX_CURSOR) { if (t->spacetype == SPACE_IMAGE) { - convert_type = TC_CURSOR_IMAGE; - } - else if (t->spacetype == SPACE_SEQ) { - convert_type = TC_CURSOR_SEQUENCER; + return &TransConvertType_CursorImage; } - else { - convert_type = TC_CURSOR_VIEW3D; + + if (t->spacetype == SPACE_SEQ) { + return &TransConvertType_CursorSequencer; } + + return &TransConvertType_Cursor3D; } - else if (!(t->options & CTX_PAINT_CURVE) && (t->spacetype == SPACE_VIEW3D) && ob && - (ob->mode == OB_MODE_SCULPT) && ob->sculpt) { - convert_type = TC_SCULPT; + if (!(t->options & CTX_PAINT_CURVE) && (t->spacetype == SPACE_VIEW3D) && ob && + (ob->mode == OB_MODE_SCULPT) && ob->sculpt) { + return &TransConvertType_Sculpt; } - else if (t->options & CTX_TEXTURE_SPACE) { - convert_type = TC_OBJECT_TEXSPACE; + if (t->options & CTX_TEXTURE_SPACE) { + return &TransConvertType_ObjectTexSpace; } - else if (t->options & CTX_EDGE_DATA) { - convert_type = TC_MESH_EDGES; + if (t->options & CTX_EDGE_DATA) { + return &TransConvertType_MeshEdge; } - else if (t->options & CTX_GPENCIL_STROKES) { - convert_type = TC_GPENCIL; + if (t->options & CTX_GPENCIL_STROKES) { + return &TransConvertType_GPencil; } - else if (t->spacetype == SPACE_IMAGE) { + if (t->spacetype == SPACE_IMAGE) { if (t->options & CTX_MASK) { - convert_type = TC_MASKING_DATA; + return &TransConvertType_Mask; } - else if (t->options & CTX_PAINT_CURVE) { + if (t->options & CTX_PAINT_CURVE) { if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) { - convert_type = TC_PAINT_CURVE_VERTS; + return &TransConvertType_PaintCurve; } } else if (t->obedit_type == OB_MESH) { - convert_type = TC_MESH_UV; + return &TransConvertType_MeshUV; } + return NULL; } - else if (t->spacetype == SPACE_ACTION) { - convert_type = TC_ACTION_DATA; + if (t->spacetype == SPACE_ACTION) { + return &TransConvertType_Action; } - else if (t->spacetype == SPACE_NLA) { - convert_type = TC_NLA_DATA; + if (t->spacetype == SPACE_NLA) { + return &TransConvertType_NLA; } - else if (t->spacetype == SPACE_SEQ) { + if (t->spacetype == SPACE_SEQ) { if (t->options & CTX_SEQUENCER_IMAGE) { - convert_type = TC_SEQ_IMAGE_DATA; - } - else { - convert_type = TC_SEQ_DATA; + return &TransConvertType_SequencerImage; } + return &TransConvertType_Sequencer; } - else if (t->spacetype == SPACE_GRAPH) { - convert_type = TC_GRAPH_EDIT_DATA; + if (t->spacetype == SPACE_GRAPH) { + return &TransConvertType_Graph; } - else if (t->spacetype == SPACE_NODE) { - convert_type = TC_NODE_DATA; + if (t->spacetype == SPACE_NODE) { + return &TransConvertType_Node; } - else if (t->spacetype == SPACE_CLIP) { + if (t->spacetype == SPACE_CLIP) { if (t->options & CTX_MOVIECLIP) { - convert_type = TC_TRACKING_DATA; + return &TransConvertType_Tracking; } - else if (t->options & CTX_MASK) { - convert_type = TC_MASKING_DATA; + if (t->options & CTX_MASK) { + return &TransConvertType_Mask; } + return NULL; } - else if (t->obedit_type != -1) { + if (t->obedit_type != -1) { if (t->obedit_type == OB_MESH) { if (t->mode == TFM_SKIN_RESIZE) { - convert_type = TC_MESH_SKIN; + return &TransConvertType_MeshSkin; } - else { - convert_type = TC_MESH_VERTS; + if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) { + return &TransConvertType_MeshVertCData; } + return &TransConvertType_Mesh; } - else if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF)) { - convert_type = TC_CURVE_VERTS; + if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF)) { + return &TransConvertType_Curve; } - else if (t->obedit_type == OB_LATTICE) { - convert_type = TC_LATTICE_VERTS; + if (t->obedit_type == OB_LATTICE) { + return &TransConvertType_Lattice; } - else if (t->obedit_type == OB_MBALL) { - convert_type = TC_MBALL_VERTS; + if (t->obedit_type == OB_MBALL) { + return &TransConvertType_MBall; } - else if (t->obedit_type == OB_ARMATURE) { - convert_type = TC_ARMATURE_VERTS; + if (t->obedit_type == OB_ARMATURE) { + return &TransConvertType_EditArmature; } + return NULL; } - else if (ob && (ob->mode & OB_MODE_POSE)) { - convert_type = TC_POSE; + if (ob && (ob->mode & OB_MODE_POSE)) { + return &TransConvertType_Pose; } - else if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { + if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { Object *ob_armature = transform_object_deform_pose_armature_get(t, ob); if (ob_armature) { *r_obj_armature = ob_armature; - convert_type = TC_POSE; + return &TransConvertType_Pose; } + return NULL; } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && - PE_start_edit(PE_get_current(t->depsgraph, t->scene, ob))) { - convert_type = TC_PARTICLE_VERTS; + if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && + PE_start_edit(PE_get_current(t->depsgraph, t->scene, ob))) { + return &TransConvertType_Particle; } - else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { + if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) { - convert_type = TC_PAINT_CURVE_VERTS; + return &TransConvertType_PaintCurve; } + return NULL; } - else if ((ob) && (ELEM(ob->mode, - OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, - OB_MODE_WEIGHT_GPENCIL, - OB_MODE_VERTEX_GPENCIL))) { + if ((ob) && (ELEM(ob->mode, + OB_MODE_PAINT_GPENCIL, + OB_MODE_SCULPT_GPENCIL, + OB_MODE_WEIGHT_GPENCIL, + OB_MODE_VERTEX_GPENCIL))) { /* In grease pencil all transformations must be canceled if not Object or Edit. */ + return NULL; } - else { - convert_type = TC_OBJECT; - } - - return convert_type; + return &TransConvertType_Object; } void createTransData(bContext *C, TransInfo *t) @@ -1376,7 +1130,14 @@ void createTransData(bContext *C, TransInfo *t) Object *ob_armature = NULL; t->data_type = convert_type_get(t, &ob_armature); - t->flag |= flags_from_data_type(t->data_type); + if (t->data_type == NULL) { + printf("edit type not implemented!\n"); + BLI_assert(t->data_len_all == -1); + t->data_len_all = 0; + return; + } + + t->flag |= t->data_type->flags; if (ob_armature) { init_TransDataContainers(t, ob_armature, &ob_armature, 1); @@ -1387,122 +1148,46 @@ void createTransData(bContext *C, TransInfo *t) init_TransDataContainers(t, ob, NULL, 0); } - switch (t->data_type) { - case TC_ACTION_DATA: - createTransActionData(C, t); - break; - case TC_POSE: - t->options |= CTX_POSE_BONE; + if (t->data_type == &TransConvertType_Object) { + t->options |= CTX_OBJECT; - /* XXX active-layer checking isn't done - * as that should probably be checked through context instead. */ - createTransPose(t); - break; - case TC_ARMATURE_VERTS: - createTransArmatureVerts(t); - break; - case TC_CURSOR_IMAGE: - createTransCursor_image(t); - break; - case TC_CURSOR_SEQUENCER: - createTransCursor_sequencer(t); - break; - case TC_CURSOR_VIEW3D: - createTransCursor_view3d(t); - 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_SKIN: - createTransMeshSkin(t); - break; - case TC_MESH_UV: - createTransUVs(C, t); - break; - case TC_NLA_DATA: - createTransNlaData(C, t); - break; - case TC_NODE_DATA: - createTransNodeData(t); - break; - case TC_OBJECT: - t->options |= CTX_OBJECT; - - /* Needed for correct Object.obmat after duplication, see: T62135. */ - BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); - - if ((t->settings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) { - t->options |= CTX_OBMODE_XFORM_OBDATA; - } - if ((t->settings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) { - t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN; - } - createTransObject(C, 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; - RegionView3D *rv3d = t->region->regiondata; - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { - /* we could have a flag to easily check an object is being transformed */ - if (v3d->camera->id.tag & LIB_TAG_DOIT) { - t->options |= CTX_CAMERA; - } - } - else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { + /* Needed for correct Object.obmat after duplication, see: T62135. */ + BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); + + if ((t->settings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) { + t->options |= CTX_OBMODE_XFORM_OBDATA; + } + if ((t->settings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) { + t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN; + } + TransConvertType_Object.createTransData(C, 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; + RegionView3D *rv3d = t->region->regiondata; + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { + /* we could have a flag to easily check an object is being transformed */ + if (v3d->camera->id.tag & LIB_TAG_DOIT) { t->options |= CTX_CAMERA; } } - break; - case TC_OBJECT_TEXSPACE: - createTransTexspace(t); - break; - case TC_PAINT_CURVE_VERTS: - createTransPaintCurveVerts(C, t); - break; - case TC_PARTICLE_VERTS: - createTransParticleVerts(t); - break; - case TC_SCULPT: - createTransSculpt(C, t); - break; - case TC_SEQ_DATA: - t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transform. */ - createTransSeqData(t); - break; - case TC_SEQ_IMAGE_DATA: + else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { + t->options |= CTX_CAMERA; + } + } + } + else { + if (t->data_type == &TransConvertType_Pose) { + t->options |= CTX_POSE_BONE; + } + else if (t->data_type == &TransConvertType_Sequencer) { + /* Sequencer has no use for floating point transform. */ + t->num.flag |= NUM_NO_FRACTION; + } + else if (t->data_type == &TransConvertType_SequencerImage) { t->obedit_type = -1; - createTransSeqImageData(t); - break; - case TC_TRACKING_DATA: - createTransTrackingData(C, t); - break; - case TC_NONE: - default: - printf("edit type not implemented!\n"); - BLI_assert(t->data_len_all == -1); - t->data_len_all = 0; - return; + } + t->data_type->createTransData(C, t); } countAndCleanTransDataContainer(t); @@ -1706,89 +1391,10 @@ void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const fl 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: - recalcData_cursor_image(t); - break; - case TC_CURSOR_SEQUENCER: - recalcData_cursor_sequencer(t); - break; - case TC_CURSOR_VIEW3D: - recalcData_cursor_view3d(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: - recalcData_mesh(t); - break; - case TC_MESH_EDGES: - recalcData_mesh_edge(t); - break; - case TC_MESH_SKIN: - recalcData_mesh_skin(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: - recalcData_objects(t); - break; - case TC_OBJECT_TEXSPACE: - recalcData_texspace(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_SEQ_IMAGE_DATA: - recalcData_sequencer_image(t); - break; - case TC_TRACKING_DATA: - recalcData_tracking(t); - break; - case TC_MBALL_VERTS: - recalcData_mball(t); - break; - case TC_LATTICE_VERTS: - recalcData_lattice(t); - break; - case TC_PARTICLE_VERTS: - recalcData_particles(t); - break; - case TC_NONE: - default: - break; + if (!t->data_type || !t->data_type->recalcData) { + return; } + t->data_type->recalcData(t); } /** \} */ diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 037fbe26c77..f32bff6dcff 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -21,6 +21,25 @@ struct TransDataCurveHandleFlags; struct TransInfo; struct bContext; +typedef struct TransConvertTypeInfo { + int flags; /* eTFlag */ + + /** + * Allocate and initialize `t->data`. + */ + void (*createTransData)(bContext *C, TransInfo *t); + + /** + * Force recalculation of data during transformation. + */ + void (*recalcData)(TransInfo *t); + + /** + * Called when the operation is finished. + */ + void (*special_aftertrans_update)(bContext *C, TransInfo *t); +} TransConvertTypeInfo; + /* transform_convert.c */ /** @@ -34,7 +53,6 @@ int special_transform_moving(TransInfo *t); 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], bool resize); void clipUVData(TransInfo *t); void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac); /** @@ -99,82 +117,53 @@ void animrecord_check_state(TransInfo *t, struct ID *id); /* transform_convert_action.c */ -void createTransActionData(bContext *C, TransInfo *t); -/* helper for recalcData() - for Action Editor transforms */ -void recalcData_actedit(TransInfo *t); -void special_aftertrans_update__actedit(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Action; /* transform_convert_armature.c */ +extern TransConvertTypeInfo TransConvertType_EditArmature; +extern TransConvertTypeInfo TransConvertType_Pose; + /** * Sets transform flags in the bones. * Returns total number of bones with #BONE_TRANSFORM. */ void transform_convert_pose_transflags_update(Object *ob, int mode, short around); -/** - * When objects array is NULL, use 't->data_container' as is. - */ -void createTransPose(TransInfo *t); -void createTransArmatureVerts(TransInfo *t); -void recalcData_edit_armature(TransInfo *t); -void recalcData_pose(TransInfo *t); -void special_aftertrans_update__pose(bContext *C, TransInfo *t); - /* transform_convert_cursor.c */ -void createTransCursor_image(TransInfo *t); -void createTransCursor_sequencer(TransInfo *t); -void createTransCursor_view3d(TransInfo *t); -void recalcData_cursor_image(TransInfo *t); -void recalcData_cursor_sequencer(TransInfo *t); -void recalcData_cursor_view3d(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_CursorImage; +extern TransConvertTypeInfo TransConvertType_CursorSequencer; +extern TransConvertTypeInfo TransConvertType_Cursor3D; /* transform_convert_curve.c */ -void createTransCurveVerts(TransInfo *t); -void recalcData_curve(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Curve; /* transform_convert_graph.c */ -/** - * It is important to note that this doesn't always act on the selection (like it's usually done), - * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a - * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the - * selected left or right handles accordingly. - * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve - * functions may need to be made aware of this. It's ugly that these act based on selection state - * anyway. - */ -void createTransGraphEditData(bContext *C, TransInfo *t); -/* helper for recalcData() - for Graph Editor transforms */ -void recalcData_graphedit(TransInfo *t); -void special_aftertrans_update__graph(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Graph; /* transform_convert_gpencil.c */ -void createTransGPencil(bContext *C, TransInfo *t); -/* force recalculation of triangles during transformation */ -void recalcData_gpencil_strokes(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_GPencil; /* transform_convert_lattice.c */ -void createTransLatticeVerts(TransInfo *t); -void recalcData_lattice(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Lattice; /* transform_convert_mask.c */ -void createTransMaskingData(bContext *C, TransInfo *t); -void recalcData_mask_common(TransInfo *t); -void special_aftertrans_update__mask(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Mask; /* transform_convert_mball.c */ -void createTransMBallVerts(TransInfo *t); -void recalcData_mball(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_MBall; /* transform_convert_mesh.c */ +extern TransConvertTypeInfo TransConvertType_Mesh; + struct TransIslandData { float (*center)[3]; float (*axismtx)[3][3]; @@ -233,84 +222,60 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3], struct TransData *r_td); void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data); -void createTransEditVerts(TransInfo *t); -void recalcData_mesh(TransInfo *t); void special_aftertrans_update__mesh(bContext *C, TransInfo *t); /* transform_convert_mesh_edge.c */ -void createTransEdge(TransInfo *t); -void recalcData_mesh_edge(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_MeshEdge; /* transform_convert_mesh_skin.c */ -void createTransMeshSkin(TransInfo *t); -void recalcData_mesh_skin(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_MeshSkin; /* transform_convert_mesh_uv.c */ -void createTransUVs(bContext *C, TransInfo *t); -/* helper for recalcData() - for Image Editor transforms */ -void recalcData_uv(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_MeshUV; + +/* transform_convert_mesh_vert_cdata.c */ + +extern TransConvertTypeInfo TransConvertType_MeshVertCData; /* transform_convert_nla.c */ -void createTransNlaData(bContext *C, TransInfo *t); -/* helper for recalcData() - for NLA Editor transforms */ -void recalcData_nla(TransInfo *t); -void special_aftertrans_update__nla(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_NLA; /* transform_convert_node.c */ -void createTransNodeData(TransInfo *t); -void flushTransNodes(TransInfo *t); -void special_aftertrans_update__node(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Node; /* transform_convert_object.c */ -void createTransObject(bContext *C, TransInfo *t); -/* helper for recalcData() - for object transforms, typically in the 3D view */ -void recalcData_objects(TransInfo *t); -void special_aftertrans_update__object(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Object; /* transform_convert_object_texspace.c */ -void createTransTexspace(TransInfo *t); -/* helper for recalcData() - for object transforms, typically in the 3D view */ -void recalcData_texspace(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_ObjectTexSpace; /* transform_convert_paintcurve.c */ -void createTransPaintCurveVerts(bContext *C, TransInfo *t); -void flushTransPaintCurve(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_PaintCurve; /* transform_convert_particle.c */ -void createTransParticleVerts(TransInfo *t); -void recalcData_particles(TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Particle; /* transform_convert_sculpt.c */ -void createTransSculpt(bContext *C, TransInfo *t); -void recalcData_sculpt(TransInfo *t); -void special_aftertrans_update__sculpt(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Sculpt; /* transform_convert_sequencer.c */ -void createTransSeqData(TransInfo *t); -/* helper for recalcData() - for sequencer transforms */ -void recalcData_sequencer(TransInfo *t); -void special_aftertrans_update__sequencer(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Sequencer; /* transform_convert_sequencer_image.c */ -void createTransSeqImageData(TransInfo *t); -void recalcData_sequencer_image(TransInfo *t); -void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_SequencerImage; /* transform_convert_tracking.c */ -void createTransTrackingData(bContext *C, TransInfo *t); -/* helper for recalcData() - for Movie Clip transforms */ -void recalcData_tracking(TransInfo *t); -void special_aftertrans_update__movieclip(bContext *C, TransInfo *t); +extern TransConvertTypeInfo TransConvertType_Tracking; diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index 71c245cd512..41635522d26 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -289,7 +289,7 @@ static int MaskLayerToTransData(TransData *td, return count; } -void createTransActionData(bContext *C, TransInfo *t) +static void createTransActionData(bContext *C, TransInfo *t) { Scene *scene = t->scene; TransData *td = NULL; @@ -311,6 +311,7 @@ void createTransActionData(bContext *C, TransInfo *t) const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; int count = 0; + int gpf_count = 0; float cfra; float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur); @@ -320,17 +321,12 @@ void createTransActionData(bContext *C, TransInfo *t) } /* filter data */ - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT); - } - else { - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/); - } + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* which side of the current frame should be allowed */ if (t->mode == TFM_TIME_EXTEND) { - t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); + t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra); } else { /* normal transform - both sides of current frame are considered */ @@ -345,10 +341,10 @@ void createTransActionData(bContext *C, TransInfo *t) * higher scaling ratios, but is faster than converting all points) */ if (adt) { - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP); } else { - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; } if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { @@ -365,13 +361,16 @@ void createTransActionData(bContext *C, TransInfo *t) } if (adt_count > 0) { + if (ELEM(ale->type, ANIMTYPE_GPLAYER, ANIMTYPE_MASKLAYER)) { + gpf_count += adt_count; + } count += adt_count; ale->tag = true; } } /* stop if trying to build list if nothing selected */ - if (count == 0) { + if (count == 0 && gpf_count == 0) { /* cleanup temp list */ ANIM_animdata_freelist(&anim_data); return; @@ -387,8 +386,9 @@ void createTransActionData(bContext *C, TransInfo *t) td = tc->data; td2d = tc->data_2d; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { - tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata"); + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { + tc->data_gpf_len = gpf_count; + tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * gpf_count, "tGPFtransdata"); tc->custom.type.use_free = true; } @@ -399,7 +399,7 @@ void createTransActionData(bContext *C, TransInfo *t) continue; } - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; { AnimData *adt; @@ -447,10 +447,10 @@ void createTransActionData(bContext *C, TransInfo *t) adt = ANIM_nla_mapping_get(&ac, ale); if (adt) { - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP); } else { - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; } if (ale->type == ANIMTYPE_GPLAYER) { @@ -558,13 +558,14 @@ static void flushTransIntFrameActionData(TransInfo *t) TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); tGPFtransdata *tfd = tc->custom.type.data; - /* flush data! */ - for (int i = 0; i < tc->data_len; i++, tfd++) { + /* flush data! + * Expects data_gpf_len to be set in the data container. */ + for (int i = 0; i < tc->data_gpf_len; i++, tfd++) { *(tfd->sdata) = round_fl_to_int(tfd->val); } } -void recalcData_actedit(TransInfo *t) +static void recalcData_actedit(TransInfo *t) { ViewLayer *view_layer = t->view_layer; SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; @@ -589,7 +590,7 @@ void recalcData_actedit(TransInfo *t) ANIM_animdata_context_getdata(&ac); /* perform flush */ - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { /* flush transform values back to actual coordinates */ flushTransIntFrameActionData(t); } @@ -735,7 +736,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act) int filter; /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY); ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION); /* loop through relevant data, removing keyframes as appropriate @@ -758,7 +759,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act) ANIM_animdata_freelist(&anim_data); } -void special_aftertrans_update__actedit(bContext *C, TransInfo *t) +static void special_aftertrans_update__actedit(bContext *C, TransInfo *t) { SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; bAnimContext ac; @@ -776,32 +777,44 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t) if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/); + short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT); /* get channels to work on */ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - /* these should all be F-Curves */ for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(&ac, ale); - FCurve *fcu = (FCurve *)ale->key_data; - - /* 3 cases here for curve cleanups: - * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done - * 2) canceled == 0 -> user confirmed the transform, - * so duplicates should be removed - * 3) canceled + duplicate -> user canceled the transform, - * but we made duplicates, so get rid of these - */ - if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) { - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); - posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */ - ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); - } - else { - posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */ + switch (ale->datatype) { + case ALE_GPFRAME: + ale->id->tag &= ~LIB_TAG_DOIT; + posttrans_gpd_clean((bGPdata *)ale->id); + break; + + case ALE_FCURVE: { + AnimData *adt = ANIM_nla_mapping_get(&ac, ale); + FCurve *fcu = (FCurve *)ale->key_data; + + /* 3 cases here for curve cleanups: + * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done + * 2) canceled == 0 -> user confirmed the transform, + * so duplicates should be removed + * 3) canceled + duplicate -> user canceled the transform, + * but we made duplicates, so get rid of these + */ + if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) { + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); + posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */ + ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); + } + else { + posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */ + } + } + break; } + + default: + BLI_assert_msg(false, "Keys cannot be transformed into this animation type."); } } @@ -847,15 +860,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t) LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { if (ale->datatype == ALE_GPFRAME) { - ale->id->tag |= LIB_TAG_DOIT; - } - } - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - if (ale->datatype == ALE_GPFRAME) { - if (ale->id->tag & LIB_TAG_DOIT) { - ale->id->tag &= ~LIB_TAG_DOIT; - posttrans_gpd_clean((bGPdata *)ale->id); - } + ale->id->tag &= ~LIB_TAG_DOIT; + posttrans_gpd_clean((bGPdata *)ale->id); } } ANIM_animdata_freelist(&anim_data); @@ -878,15 +884,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t) LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { if (ale->datatype == ALE_MASKLAY) { - ale->id->tag |= LIB_TAG_DOIT; - } - } - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - if (ale->datatype == ALE_MASKLAY) { - if (ale->id->tag & LIB_TAG_DOIT) { - ale->id->tag &= ~LIB_TAG_DOIT; - posttrans_mask_clean((Mask *)ale->id); - } + ale->id->tag &= ~LIB_TAG_DOIT; + posttrans_mask_clean((Mask *)ale->id); } } ANIM_animdata_freelist(&anim_data); @@ -927,3 +926,10 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Action = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransActionData, + /* recalcData */ recalcData_actedit, + /* special_aftertrans_update */ special_aftertrans_update__actedit, +}; diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index e1b25acb21e..97d9ab2964a 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -93,8 +93,8 @@ static void autokeyframe_pose( KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); ListBase nla_cache = {NULL, NULL}; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, - (float)CFRA); + const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( + depsgraph, (float)scene->r.cfra); eInsertKeyFlags flag = 0; /* flag is initialized from UserPref keyframing settings @@ -701,7 +701,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr td->con = pchan->constraints.first; } -void createTransPose(TransInfo *t) +static void createTransPose(bContext *UNUSED(C), TransInfo *t) { Main *bmain = CTX_data_main(t->context); @@ -879,7 +879,7 @@ void createTransPose(TransInfo *t) } } -void createTransArmatureVerts(TransInfo *t) +static void createTransArmatureVerts(bContext *UNUSED(C), TransInfo *t) { t->data_len_all = 0; @@ -1189,10 +1189,10 @@ static void restoreBones(TransDataContainer *tc) } } -void recalcData_edit_armature(TransInfo *t) +static void recalcData_edit_armature(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -1412,7 +1412,7 @@ static void restoreMirrorPoseBones(TransDataContainer *tc) } } -void recalcData_pose(TransInfo *t) +static void recalcData_pose(TransInfo *t) { if (t->mode == TFM_BONESIZE) { /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be @@ -1684,7 +1684,7 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob) } } -void special_aftertrans_update__pose(bContext *C, TransInfo *t) +static void special_aftertrans_update__pose(bContext *C, TransInfo *t) { Object *ob; @@ -1768,3 +1768,17 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_EditArmature = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransArmatureVerts, + /* recalcData */ recalcData_edit_armature, + /* special_aftertrans_update */ NULL, +}; + +TransConvertTypeInfo TransConvertType_Pose = { + /* flags */ 0, + /* createTransData */ createTransPose, + /* recalcData */ recalcData_pose, + /* special_aftertrans_update */ special_aftertrans_update__pose, +}; diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c index 5e6eee192f2..0bf6f06a9f2 100644 --- a/source/blender/editors/transform/transform_convert_cursor.c +++ b/source/blender/editors/transform/transform_convert_cursor.c @@ -82,13 +82,13 @@ static void recalcData_cursor_2D_impl(TransInfo *t) /** \name Image Cursor * \{ */ -void createTransCursor_image(TransInfo *t) +static void createTransCursor_image(bContext *UNUSED(C), TransInfo *t) { SpaceImage *sima = t->area->spacedata.first; createTransCursor_2D_impl(t, sima->cursor); } -void recalcData_cursor_image(TransInfo *t) +static void recalcData_cursor_image(TransInfo *t) { recalcData_cursor_2D_impl(t); } @@ -99,7 +99,7 @@ void recalcData_cursor_image(TransInfo *t) /** \name Sequencer Cursor * \{ */ -void createTransCursor_sequencer(TransInfo *t) +static void createTransCursor_sequencer(bContext *UNUSED(C), TransInfo *t) { SpaceSeq *sseq = t->area->spacedata.first; if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) { @@ -108,7 +108,7 @@ void createTransCursor_sequencer(TransInfo *t) createTransCursor_2D_impl(t, sseq->cursor); } -void recalcData_cursor_sequencer(TransInfo *t) +static void recalcData_cursor_sequencer(TransInfo *t) { recalcData_cursor_2D_impl(t); } @@ -119,7 +119,7 @@ void recalcData_cursor_sequencer(TransInfo *t) /** \name View 3D Cursor * \{ */ -void createTransCursor_view3d(TransInfo *t) +static void createTransCursor_view3d(bContext *UNUSED(C), TransInfo *t) { TransData *td; @@ -178,9 +178,30 @@ void createTransCursor_view3d(TransInfo *t) td->ext->rotOrder = cursor->rotation_mode; } -void recalcData_cursor_view3d(TransInfo *t) +static void recalcData_cursor_view3d(TransInfo *t) { DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); } /** \} */ + +TransConvertTypeInfo TransConvertType_CursorImage = { + /* flags */ T_2D_EDIT, + /* createTransData */ createTransCursor_image, + /* recalcData */ recalcData_cursor_image, + /* special_aftertrans_update */ NULL, +}; + +TransConvertTypeInfo TransConvertType_CursorSequencer = { + /* flags */ T_2D_EDIT, + /* createTransData */ createTransCursor_sequencer, + /* recalcData */ recalcData_cursor_sequencer, + /* special_aftertrans_update */ NULL, +}; + +TransConvertTypeInfo TransConvertType_Cursor3D = { + /* flags */ 0, + /* createTransData */ createTransCursor_view3d, + /* recalcData */ recalcData_cursor_view3d, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 51acfb2a788..404b1293208 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -62,7 +62,7 @@ static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const boo return flag; } -void createTransCurveVerts(TransInfo *t) +static void createTransCurveVerts(bContext *UNUSED(C), TransInfo *t) { #define SEL_F1 (1 << 0) @@ -415,10 +415,10 @@ void createTransCurveVerts(TransInfo *t) #undef SEL_F3 } -void recalcData_curve(TransInfo *t) +static void recalcData_curve(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -446,3 +446,10 @@ void recalcData_curve(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Curve = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransCurveVerts, + /* recalcData */ recalcData_curve, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index a88d42b7f30..0029eaefaba 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -672,7 +672,7 @@ static void createTransGPencil_strokes(bContext *C, } } -void createTransGPencil(bContext *C, TransInfo *t) +static void createTransGPencil(bContext *C, TransInfo *t) { if (t->data_container_len == 0) { return; @@ -685,7 +685,7 @@ void createTransGPencil(bContext *C, TransInfo *t) bGPdata *gpd = obact->data; BLI_assert(gpd != NULL); - const int cfra_scene = CFRA; + const int cfra_scene = scene->r.cfra; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); const bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != @@ -737,7 +737,7 @@ void createTransGPencil(bContext *C, TransInfo *t) } } -void recalcData_gpencil_strokes(TransInfo *t) +static void recalcData_gpencil_strokes(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); GHash *strokes = BLI_ghash_ptr_new(__func__); @@ -762,3 +762,10 @@ void recalcData_gpencil_strokes(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_GPencil = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransGPencil, + /* recalcData */ recalcData_gpencil_strokes, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index 2039daee386..aca2439d5fb 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -199,7 +199,16 @@ static void graph_key_shortest_dist( } } -void createTransGraphEditData(bContext *C, TransInfo *t) +/** + * It is important to note that this doesn't always act on the selection (like it's usually done), + * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a + * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the + * selected left or right handles accordingly. + * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve + * functions may need to be made aware of this. It's ugly that these act based on selection state + * anyway. + */ +static void createTransGraphEditData(bContext *C, TransInfo *t) { SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; Scene *scene = t->scene; @@ -232,13 +241,14 @@ void createTransGraphEditData(bContext *C, TransInfo *t) anim_map_flag |= ANIM_get_normalization_flags(&ac); /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE | + ANIMFILTER_FCURVESONLY); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* which side of the current frame should be allowed */ /* XXX we still want this mode, but how to get this using standard transform too? */ if (t->mode == TFM_TIME_EXTEND) { - t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); + t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra); } else { /* normal transform - both sides of current frame are considered */ @@ -263,10 +273,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t) * higher scaling ratios, but is faster than converting all points) */ if (adt) { - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP); } else { - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; } for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { @@ -369,10 +379,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t) * higher scaling ratios, but is faster than converting all points) */ if (adt) { - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP); } else { - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; } unit_scale = ANIM_unit_mapping_get_factor( @@ -560,10 +570,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t) * higher scaling ratios, but is faster than converting all points) */ if (adt) { - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP); } else { - cfra = (float)CFRA; + cfra = (float)scene->r.cfra; } for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { @@ -885,7 +895,7 @@ static void remake_graph_transdata(TransInfo *t, ListBase *anim_data) } } -void recalcData_graphedit(TransInfo *t) +static void recalcData_graphedit(TransInfo *t) { SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; ViewLayer *view_layer = t->view_layer; @@ -915,7 +925,8 @@ void recalcData_graphedit(TransInfo *t) flushTransGraphData(t); /* get curves to check if a re-sort is needed */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE | + ANIMFILTER_FCURVESONLY); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* now test if there is a need to re-sort */ @@ -932,7 +943,7 @@ void recalcData_graphedit(TransInfo *t) dosort++; } else { - calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG); + BKE_fcurve_handles_recalc_ex(fcu, BEZT_FLAG_TEMP_TAG); } /* set refresh tags for objects using this animation, @@ -958,7 +969,7 @@ void recalcData_graphedit(TransInfo *t) /** \name Special After Transform Graph * \{ */ -void special_aftertrans_update__graph(bContext *C, TransInfo *t) +static void special_aftertrans_update__graph(bContext *C, TransInfo *t) { SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; bAnimContext ac; @@ -975,7 +986,8 @@ void special_aftertrans_update__graph(bContext *C, TransInfo *t) if (ac.datatype) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE); + short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE | + ANIMFILTER_FCURVESONLY); /* get channels to work on */ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); @@ -1018,3 +1030,10 @@ void special_aftertrans_update__graph(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Graph = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransGraphEditData, + /* recalcData */ recalcData_graphedit, + /* special_aftertrans_update */ special_aftertrans_update__graph, +}; diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c index f02d4e94448..b77538dc249 100644 --- a/source/blender/editors/transform/transform_convert_lattice.c +++ b/source/blender/editors/transform/transform_convert_lattice.c @@ -25,7 +25,7 @@ /** \name Curve/Surfaces Transform Creation * \{ */ -void createTransLatticeVerts(TransInfo *t) +static void createTransLatticeVerts(bContext *UNUSED(C), TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -98,10 +98,10 @@ void createTransLatticeVerts(TransInfo *t) } } -void recalcData_lattice(TransInfo *t) +static void recalcData_lattice(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -114,3 +114,10 @@ void recalcData_lattice(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Lattice = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransLatticeVerts, + /* recalcData */ recalcData_lattice, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index b07d2bda0c5..2dca59a5da1 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -117,7 +117,7 @@ static void MaskPointToTransData(Scene *scene, const bool is_sel_any = MASKPOINT_ISSEL_ANY(point); float parent_matrix[3][3], parent_inverse_matrix[3][3]; - BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix); + BKE_mask_point_parent_matrix_get(point, scene->r.cfra, parent_matrix); invert_m3_m3(parent_inverse_matrix, parent_matrix); if (is_prop_edit || is_sel_point) { @@ -245,7 +245,7 @@ static void MaskPointToTransData(Scene *scene, } } -void createTransMaskingData(bContext *C, TransInfo *t) +static void createTransMaskingData(bContext *C, TransInfo *t) { Scene *scene = CTX_data_scene(C); Mask *mask = CTX_data_edit_mask(C); @@ -416,7 +416,7 @@ static void flushTransMasking(TransInfo *t) } } -void recalcData_mask_common(TransInfo *t) +static void recalcData_mask_common(TransInfo *t) { Mask *mask = CTX_data_edit_mask(t->context); @@ -431,7 +431,7 @@ void recalcData_mask_common(TransInfo *t) /** \name Special After Transform Mask * \{ */ -void special_aftertrans_update__mask(bContext *C, TransInfo *t) +static void special_aftertrans_update__mask(bContext *C, TransInfo *t) { Mask *mask = NULL; @@ -455,7 +455,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t) if (IS_AUTOKEY_ON(t->scene)) { Scene *scene = t->scene; - if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) { + if (ED_mask_layer_shape_auto_key_select(mask, scene->r.cfra)) { WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); DEG_id_tag_update(&mask->id, 0); } @@ -463,3 +463,10 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Mask = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransMaskingData, + /* recalcData */ recalcData_mask_common, + /* special_aftertrans_update */ special_aftertrans_update__mask, +}; diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c index 7cba4f97886..7ae93524d0b 100644 --- a/source/blender/editors/transform/transform_convert_mball.c +++ b/source/blender/editors/transform/transform_convert_mball.c @@ -22,7 +22,7 @@ /** \name Meta Elements Transform Creation * \{ */ -void createTransMBallVerts(TransInfo *t) +static void createTransMBallVerts(bContext *UNUSED(C), TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { MetaBall *mb = (MetaBall *)tc->obedit->data; @@ -119,10 +119,10 @@ void createTransMBallVerts(TransInfo *t) /** \name Recalc Meta Ball * \{ */ -void recalcData_mball(TransInfo *t) +static void recalcData_mball(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->data_len) { @@ -132,3 +132,10 @@ void recalcData_mball(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_MBall = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransMBallVerts, + /* recalcData */ recalcData_mball, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index d4b12142162..b5a85f57b84 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1408,7 +1408,6 @@ static void VertsToTransData(TransInfo *t, TransDataExtension *tx, BMEditMesh *em, BMVert *eve, - float *bweight, const struct TransIslandData *island_data, const int island_index) { @@ -1449,17 +1448,13 @@ static void VertsToTransData(TransInfo *t, td->ext = NULL; td->val = NULL; td->extra = eve; - if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) { - td->val = bweight; - td->ival = *bweight; - } - else if (t->mode == TFM_SHRINKFATTEN) { + if (t->mode == TFM_SHRINKFATTEN) { td->ext = tx; tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT); } } -void createTransEditVerts(TransInfo *t) +static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransDataExtension *tx = NULL; @@ -1589,17 +1584,6 @@ void createTransEditVerts(TransInfo *t) "TransObData ext"); } - int cd_vert_bweight_offset = -1; - int cd_vert_crease_offset = -1; - if (t->mode == TFM_BWEIGHT) { - BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); - cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - } - else if (t->mode == TFM_VERT_CREASE) { - BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE); - cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); - } - TransData *tob = tc->data; TransDataMirror *td_mirror = tc->data_mirror; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { @@ -1632,15 +1616,9 @@ void createTransEditVerts(TransInfo *t) td_mirror++; } else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float *bweight = (cd_vert_bweight_offset != -1) ? - BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : - (cd_vert_crease_offset != -1) ? - BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) : - NULL; - /* Do not use the island center in case we are using islands * only to get axis for snap/rotate to normal... */ - VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index); + VertsToTransData(t, tob, tx, em, eve, &island_data, island_index); if (tx) { tx++; } @@ -1940,7 +1918,7 @@ static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_ } /* With projection, transform isn't affine. */ - if (activeSnap_with_project(t)) { + if (activeSnap_SnappingIndividual(t)) { if (partial_for_looptri == PARTIAL_TYPE_GROUP) { partial_for_looptri = PARTIAL_TYPE_ALL; } @@ -2051,12 +2029,12 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc) } } -void recalcData_mesh(TransInfo *t) +static void recalcData_mesh(TransInfo *t) { bool is_canceling = t->state == TRANS_CANCEL; /* Apply corrections. */ if (!is_canceling) { - applyProject(t); + applySnappingIndividual(t); bool do_mirror = !(t->flag & T_NO_MIRROR); FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -2151,3 +2129,10 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Mesh = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransEditVerts, + /* recalcData */ recalcData_mesh, + /* special_aftertrans_update */ special_aftertrans_update__mesh, +}; diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 2d6c6a933d6..becf3c7ce5a 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -23,7 +23,7 @@ /** \name Edge (for crease) Transform Creation * \{ */ -void createTransEdge(TransInfo *t) +static void createTransEdge(bContext *UNUSED(C), TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -99,8 +99,8 @@ void createTransEdge(TransInfo *t) td->ext = NULL; fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset); - td->val = fl_ptr; - td->ival = *fl_ptr; + td->loc = fl_ptr; + td->iloc[0] = *fl_ptr; td++; } @@ -108,7 +108,7 @@ void createTransEdge(TransInfo *t) } } -void recalcData_mesh_edge(TransInfo *t) +static void recalcData_mesh_edge(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); @@ -116,3 +116,10 @@ void recalcData_mesh_edge(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_MeshEdge = { + /* flags */ T_EDIT, + /* createTransData */ createTransEdge, + /* recalcData */ recalcData_mesh_edge, + /* special_aftertrans_update */ special_aftertrans_update__mesh, +}; diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c index fdc2ba59035..376e559181e 100644 --- a/source/blender/editors/transform/transform_convert_mesh_skin.c +++ b/source/blender/editors/transform/transform_convert_mesh_skin.c @@ -66,7 +66,7 @@ static void tc_mesh_skin_transdata_create(TransDataBasic *td, td->extra = eve; } -void createTransMeshSkin(TransInfo *t) +static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t) { BLI_assert(t->mode == TFM_SKIN_RESIZE); FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -271,7 +271,7 @@ static void tc_mesh_skin_apply_to_mirror(TransInfo *t) } } -void recalcData_mesh_skin(TransInfo *t) +static void recalcData_mesh_skin(TransInfo *t) { bool is_canceling = t->state == TRANS_CANCEL; /* mirror modifier clipping? */ @@ -289,3 +289,10 @@ void recalcData_mesh_skin(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_MeshSkin = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransMeshSkin, + /* recalcData */ recalcData_mesh_skin, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c index 18868643b6d..d95bc7b976f 100644 --- a/source/blender/editors/transform/transform_convert_mesh_uv.c +++ b/source/blender/editors/transform/transform_convert_mesh_uv.c @@ -234,11 +234,10 @@ static void uv_set_connectivity_distance(BMesh *bm, float *dists, const float as MEM_freeN(dists_prev); } -void createTransUVs(bContext *C, TransInfo *t) +static void createTransUVs(bContext *C, TransInfo *t) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = t->scene; - ToolSettings *ts = CTX_data_tool_settings(C); const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; @@ -266,8 +265,7 @@ void createTransUVs(bContext *C, TransInfo *t) /* count */ if (is_island_center) { /* create element map with island information */ - const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; - elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true); + elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true); if (elementmap == NULL) { continue; } @@ -448,7 +446,7 @@ static void flushTransUVs(TransInfo *t) } } -void recalcData_uv(TransInfo *t) +static void recalcData_uv(TransInfo *t) { SpaceImage *sima = t->area->spacedata.first; @@ -465,3 +463,10 @@ void recalcData_uv(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_MeshUV = { + /* flags */ (T_EDIT | T_POINTS | T_2D_EDIT), + /* createTransData */ createTransUVs, + /* recalcData */ recalcData_uv, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c new file mode 100644 index 00000000000..f05688f3325 --- /dev/null +++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ + +/** \file + * \ingroup edtransform + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_crazyspace.h" +#include "BKE_editmesh.h" +#include "BKE_modifier.h" +#include "BKE_scene.h" + +#include "ED_mesh.h" + +#include "DEG_depsgraph_query.h" + +#include "transform.h" +#include "transform_orientations.h" + +#include "transform_convert.h" + +/* -------------------------------------------------------------------- */ +/** \name Edit Mesh #CD_BWEIGHT and #CD_CREASE Transform Creation + * \{ */ + +static float *tc_mesh_cdata_transdata_center(const struct TransIslandData *island_data, + const int island_index, + BMVert *eve) +{ + if (island_data->center && island_index != -1) { + return island_data->center[island_index]; + } + return eve->co; +} + +static void tc_mesh_cdata_transdata_create(TransDataBasic *td, + BMVert *eve, + float *weight, + const struct TransIslandData *island_data, + const int island_index) +{ + BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0); + + td->loc = weight; + td->iloc[0] = *weight; + + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + td->flag |= TD_SELECTED; + } + + copy_v3_v3(td->center, tc_mesh_cdata_transdata_center(island_data, island_index, eve)); + td->extra = eve; +} + +static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t) +{ + BLI_assert(ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + Mesh *me = tc->obedit->data; + BMesh *bm = em->bm; + BMVert *eve; + BMIter iter; + float mtx[3][3], smtx[3][3]; + int a; + const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; + + struct TransIslandData island_data = {NULL}; + struct TransMirrorData mirror_data = {NULL}; + struct TransMeshDataCrazySpace crazyspace_data = {NULL}; + + /* Support other objects using PET to adjust these, unless connected is enabled. */ + if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) { + continue; + } + + int cd_offset = -1; + if (t->mode == TFM_BWEIGHT) { + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT); + cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); + } + else { + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE); + cd_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); + } + + if (cd_offset == -1) { + continue; + } + + int data_len = 0; + if (prop_mode) { + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + data_len++; + } + } + } + else { + data_len = bm->totvertsel; + } + + if (data_len == 0) { + continue; + } + + const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); + if (is_island_center) { + /* In this specific case, near-by vertices will need to know + * the island of the nearest connected vertex. */ + const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && + (t->around == V3D_AROUND_LOCAL_ORIGINS) && + (em->selectmode & SCE_SELECT_VERTEX)); + + const bool calc_island_center = false; + const bool calc_island_axismtx = false; + + transform_convert_mesh_islands_calc( + em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); + } + + copy_m3_m4(mtx, tc->obedit->obmat); + /* we use a pseudo-inverse so that when one of the axes is scaled to 0, + * matrix inversion still works and we can still moving along the other */ + pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); + + /* Original index of our connected vertex when connected distances are calculated. + * Optional, allocate if needed. */ + int *dists_index = NULL; + float *dists = NULL; + if (prop_mode & T_PROP_CONNECTED) { + dists = MEM_mallocN(bm->totvert * sizeof(float), __func__); + if (is_island_center) { + dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__); + } + transform_convert_mesh_connectivity_distance(em->bm, mtx, dists, dists_index); + } + + /* Create TransDataMirror. */ + if (tc->use_mirror_axis_any) { + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + bool use_select = (t->flag & T_PROP_EDIT) == 0; + const bool mirror_axis[3] = { + tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z}; + transform_convert_mesh_mirrordata_calc( + em, use_select, use_topology, mirror_axis, &mirror_data); + + if (mirror_data.vert_map) { + tc->data_mirror_len = mirror_data.mirror_elem_len; + tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror), + __func__); + + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { + if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (mirror_data.vert_map[a].index != -1) { + data_len--; + } + } + } + } + } + + /* Detect CrazySpace [tm]. */ + transform_convert_mesh_crazyspace_detect(t, tc, em, &crazyspace_data); + + /* Create TransData. */ + BLI_assert(data_len >= 1); + tc->data_len = data_len; + tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); + + TransData *td = tc->data; + TransDataMirror *td_mirror = tc->data_mirror; + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { + if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + continue; + } + + int island_index = -1; + if (island_data.island_vert_map) { + const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a; + island_index = island_data.island_vert_map[connected_index]; + } + + float *weight = BM_ELEM_CD_GET_VOID_P(eve, cd_offset); + if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) { + tc_mesh_cdata_transdata_create( + (TransDataBasic *)td_mirror, eve, weight, &island_data, island_index); + + int elem_index = mirror_data.vert_map[a].index; + BMVert *v_src = BM_vert_at_index(bm, elem_index); + + td_mirror->flag |= mirror_data.vert_map[a].flag; + td_mirror->loc_src = BM_ELEM_CD_GET_VOID_P(v_src, cd_offset); + td_mirror++; + } + else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + tc_mesh_cdata_transdata_create( + (TransDataBasic *)td, eve, weight, &island_data, island_index); + + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { + createSpaceNormal(td->axismtx, eve->no); + } + else { + /* Setting normals */ + copy_v3_v3(td->axismtx[2], eve->no); + td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] = + td->axismtx[1][1] = td->axismtx[1][2] = 0.0f; + } + + if (prop_mode) { + if (prop_mode & T_PROP_CONNECTED) { + td->dist = dists[a]; + } + else { + td->flag |= TD_NOTCONNECTED; + td->dist = FLT_MAX; + } + } + + /* CrazySpace */ + transform_convert_mesh_crazyspace_transdata_set( + mtx, + smtx, + crazyspace_data.defmats ? crazyspace_data.defmats[a] : NULL, + crazyspace_data.quats && BM_elem_flag_test(eve, BM_ELEM_TAG) ? + crazyspace_data.quats[a] : + NULL, + td); + + td++; + } + } + + transform_convert_mesh_islanddata_free(&island_data); + transform_convert_mesh_mirrordata_free(&mirror_data); + transform_convert_mesh_crazyspace_free(&crazyspace_data); + if (dists) { + MEM_freeN(dists); + } + if (dists_index) { + MEM_freeN(dists_index); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Recalc Mesh Data + * \{ */ + +static void tc_mesh_cdata_apply_to_mirror(TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (tc->use_mirror_axis_any) { + TransDataMirror *td_mirror = tc->data_mirror; + for (int i = 0; i < tc->data_mirror_len; i++, td_mirror++) { + td_mirror->loc[0] = td_mirror->loc_src[0]; + } + } + } +} + +static void recalcData_mesh_cdata(TransInfo *t) +{ + bool is_canceling = t->state == TRANS_CANCEL; + /* mirror modifier clipping? */ + if (!is_canceling) { + if (!(t->flag & T_NO_MIRROR)) { + tc_mesh_cdata_apply_to_mirror(t); + } + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BKE_editmesh_looptri_and_normals_calc(em); + } +} + +/** \} */ + +TransConvertTypeInfo TransConvertType_MeshVertCData = { + /* flags */ (T_EDIT | T_POINTS), + /* createTransData */ createTransMeshVertCData, + /* recalcData */ recalcData_mesh_cdata, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index 2fa8fcf65ba..cfa933d1600 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -59,7 +59,7 @@ typedef struct TransDataNla { /** \name NLA Transform Creation * \{ */ -void createTransNlaData(bContext *C, TransInfo *t) +static void createTransNlaData(bContext *C, TransInfo *t) { Scene *scene = t->scene; SpaceNla *snla = NULL; @@ -82,12 +82,13 @@ void createTransNlaData(bContext *C, TransInfo *t) snla = (SpaceNla *)ac.sl; /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_FCURVESONLY); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* which side of the current frame should be allowed */ if (t->mode == TFM_TIME_EXTEND) { - t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); + t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra); } else { /* normal transform - both sides of current frame are considered */ @@ -108,10 +109,10 @@ void createTransNlaData(bContext *C, TransInfo *t) /* transition strips can't get directly transformed */ if (strip->type != NLASTRIP_TYPE_TRANSITION) { if (strip->flag & NLASTRIP_FLAG_SELECT) { - if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) { + if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) { count++; } - if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) { + if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) { count++; } } @@ -122,7 +123,7 @@ void createTransNlaData(bContext *C, TransInfo *t) /* stop if trying to build list if nothing selected */ if (count == 0) { /* clear temp metas that may have been created but aren't needed now - * because they fell on the wrong side of CFRA + * because they fell on the wrong side of scene->r.cfra */ for (ale = anim_data.first; ale; ale = ale->next) { NlaTrack *nlt = (NlaTrack *)ale->data; @@ -181,12 +182,12 @@ void createTransNlaData(bContext *C, TransInfo *t) tdn->h2[0] = strip->end; tdn->h2[1] = yval; - center[0] = (float)CFRA; + center[0] = (float)scene->r.cfra; center[1] = yval; center[2] = 0.0f; /* set td's based on which handles are applicable */ - if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) { + if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) { /* just set tdn to assume that it only has one handle for now */ tdn->handle = -1; @@ -206,7 +207,7 @@ void createTransNlaData(bContext *C, TransInfo *t) td->extra = tdn; td++; } - if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) { + if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) { /* if tdn is already holding the start handle, * then we're doing both, otherwise, only end */ tdn->handle = (tdn->handle) ? 2 : 1; @@ -248,7 +249,7 @@ void createTransNlaData(bContext *C, TransInfo *t) ANIM_animdata_freelist(&anim_data); } -void recalcData_nla(TransInfo *t) +static void recalcData_nla(TransInfo *t) { SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; @@ -463,7 +464,7 @@ void recalcData_nla(TransInfo *t) /** \name Special After Transform NLA * \{ */ -void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t)) +static void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t)) { bAnimContext ac; @@ -475,7 +476,7 @@ void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t)) if (ac.datatype) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT); + short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY); /* get channels to work on */ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); @@ -505,3 +506,10 @@ void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t)) } /** \} */ + +TransConvertTypeInfo TransConvertType_NLA = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransNlaData, + /* recalcData */ recalcData_nla, + /* special_aftertrans_update */ special_aftertrans_update__nla, +}; diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index 8281052c314..e18f75b71ae 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -89,7 +89,7 @@ static bool is_node_parent_select(bNode *node) return false; } -void createTransNodeData(TransInfo *t) +static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) { const float dpi_fac = UI_DPI_FAC; SpaceNode *snode = t->area->spacedata.first; @@ -150,7 +150,7 @@ void createTransNodeData(TransInfo *t) /** \name Node Transform Creation * \{ */ -void flushTransNodes(TransInfo *t) +static void flushTransNodes(TransInfo *t) { const float dpi_fac = UI_DPI_FAC; @@ -220,7 +220,7 @@ void flushTransNodes(TransInfo *t) /** \name Special After Transform Node * \{ */ -void special_aftertrans_update__node(bContext *C, TransInfo *t) +static void special_aftertrans_update__node(bContext *C, TransInfo *t) { struct Main *bmain = CTX_data_main(C); const bool canceled = (t->state == TRANS_CANCEL); @@ -249,3 +249,10 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Node = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransNodeData, + /* recalcData */ flushTransNodes, + /* special_aftertrans_update */ special_aftertrans_update__node, +}; diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 5879a65eb4b..be5f59c61c0 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -480,7 +480,7 @@ static void clear_trans_object_base_flags(TransInfo *t) } } -void createTransObject(bContext *C, TransInfo *t) +static void createTransObject(bContext *C, TransInfo *t) { Main *bmain = CTX_data_main(C); TransData *td = NULL; @@ -732,8 +732,8 @@ static void autokeyframe_object( KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); ListBase dsources = {NULL, NULL}; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, - (float)CFRA); + const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( + depsgraph, (float)scene->r.cfra); eInsertKeyFlags flag = 0; /* Get flags used for inserting keyframes. */ @@ -860,12 +860,12 @@ static bool motionpath_need_update_object(Scene *scene, Object *ob) /** \name Recalc Data object * \{ */ -void recalcData_objects(TransInfo *t) +static void recalcData_objects(TransInfo *t) { bool motionpath_update = false; if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -918,7 +918,7 @@ void recalcData_objects(TransInfo *t) /** \name Special After Transform Object * \{ */ -void special_aftertrans_update__object(bContext *C, TransInfo *t) +static void special_aftertrans_update__object(bContext *C, TransInfo *t) { BLI_assert(t->options & CTX_OBJECT); @@ -991,3 +991,10 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Object = { + /* flags */ 0, + /* createTransData */ createTransObject, + /* recalcData */ recalcData_objects, + /* special_aftertrans_update */ special_aftertrans_update__object, +}; diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c index 1f58ec80f02..39bf22a9af9 100644 --- a/source/blender/editors/transform/transform_convert_object_texspace.c +++ b/source/blender/editors/transform/transform_convert_object_texspace.c @@ -29,7 +29,7 @@ * * \{ */ -void createTransTexspace(TransInfo *t) +static void createTransTexspace(bContext *UNUSED(C), TransInfo *t) { ViewLayer *view_layer = t->view_layer; TransData *td; @@ -86,11 +86,11 @@ void createTransTexspace(TransInfo *t) /** \name Recalc Data object * \{ */ -void recalcData_texspace(TransInfo *t) +static void recalcData_texspace(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -106,3 +106,10 @@ void recalcData_texspace(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_ObjectTexSpace = { + /* flags */ 0, + /* createTransData */ createTransTexspace, + /* recalcData */ recalcData_texspace, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c index b2566016496..61b1cb9493b 100644 --- a/source/blender/editors/transform/transform_convert_paintcurve.c +++ b/source/blender/editors/transform/transform_convert_paintcurve.c @@ -108,7 +108,7 @@ static void PaintCurvePointToTransData(PaintCurvePoint *pcp, } } -void createTransPaintCurveVerts(bContext *C, TransInfo *t) +static void createTransPaintCurveVerts(bContext *C, TransInfo *t) { Paint *paint = BKE_paint_get_active_from_context(C); PaintCurve *pc; @@ -188,7 +188,7 @@ void createTransPaintCurveVerts(bContext *C, TransInfo *t) /** \name Paint Curve Transform Flush * \{ */ -void flushTransPaintCurve(TransInfo *t) +static void flushTransPaintCurve(TransInfo *t) { int i; @@ -204,3 +204,10 @@ void flushTransPaintCurve(TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_PaintCurve = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransPaintCurveVerts, + /* recalcData */ flushTransPaintCurve, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index d7b0f378c8a..41f37b34af0 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -28,7 +28,7 @@ /** \name Particle Edit Transform Creation * \{ */ -void createTransParticleVerts(TransInfo *t) +static void createTransParticleVerts(bContext *UNUSED(C), TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -235,12 +235,19 @@ static void flushTransParticles(TransInfo *t) /** \name Recalc Transform Particles Data * \{ */ -void recalcData_particles(TransInfo *t) +static void recalcData_particles(TransInfo *t) { if (t->state != TRANS_CANCEL) { - applyProject(t); + applySnappingIndividual(t); } flushTransParticles(t); } /** \} */ + +TransConvertTypeInfo TransConvertType_Particle = { + /* flags */ T_POINTS, + /* createTransData */ createTransParticleVerts, + /* recalcData */ recalcData_particles, + /* special_aftertrans_update */ NULL, +}; diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index 5bf6bfa8644..95958b816ab 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -23,7 +23,7 @@ /** \name Sculpt Transform Creation * \{ */ -void createTransSculpt(bContext *C, TransInfo *t) +static void createTransSculpt(bContext *C, TransInfo *t) { TransData *td; @@ -94,13 +94,13 @@ void createTransSculpt(bContext *C, TransInfo *t) /** \name Recalc Data object * \{ */ -void recalcData_sculpt(TransInfo *t) +static void recalcData_sculpt(TransInfo *t) { Object *ob = OBACT(t->view_layer); ED_sculpt_update_modal_transform(t->context, ob); } -void special_aftertrans_update__sculpt(bContext *C, TransInfo *t) +static void special_aftertrans_update__sculpt(bContext *C, TransInfo *t) { Scene *scene = t->scene; if (!BKE_id_is_editable(CTX_data_main(C), &scene->id)) { @@ -114,3 +114,10 @@ void special_aftertrans_update__sculpt(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Sculpt = { + /* flags */ 0, + /* createTransData */ createTransSculpt, + /* recalcData */ recalcData_sculpt, + /* special_aftertrans_update */ special_aftertrans_update__sculpt, +}; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 849641fd320..eefc9d0cc2a 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -90,7 +90,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag) if (t->mode == TFM_TIME_EXTEND) { /* *** Extend Transform *** */ - int cfra = CFRA; + int cfra = scene->r.cfra; int left = SEQ_time_left_handle_frame_get(scene, seq); int right = SEQ_time_right_handle_frame_get(scene, seq); @@ -465,7 +465,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t) return dependent; } -void createTransSeqData(TransInfo *t) +static void createTransSeqData(bContext *UNUSED(C), TransInfo *t) { Scene *scene = t->scene; Editing *ed = SEQ_editing_get(t->scene); @@ -489,7 +489,7 @@ void createTransSeqData(TransInfo *t) } tc->custom.type.free_cb = freeSeqData; - t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); + t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra); count = SeqTransCount(t, ed->seqbasep); @@ -659,7 +659,7 @@ static void flushTransSeq(TransInfo *t) SEQ_collection_free(transformed_strips); } -void recalcData_sequencer(TransInfo *t) +static void recalcData_sequencer(TransInfo *t) { TransData *td; int a; @@ -689,7 +689,7 @@ void recalcData_sequencer(TransInfo *t) /** \name Special After Transform Sequencer * \{ */ -void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t) +static void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t) { if (t->state == TRANS_CANCEL) { return; @@ -734,3 +734,10 @@ void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2]) } /** \} */ + +TransConvertTypeInfo TransConvertType_Sequencer = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransSeqData, + /* recalcData */ recalcData_sequencer, + /* special_aftertrans_update */ special_aftertrans_update__sequencer, +}; diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c index 46606d5814f..3d0c3ddaa4c 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.c +++ b/source/blender/editors/transform/transform_convert_sequencer_image.c @@ -105,7 +105,7 @@ static void freeSeqData(TransInfo *UNUSED(t), MEM_freeN(td->extra); } -void createTransSeqImageData(TransInfo *t) +static void createTransSeqImageData(bContext *UNUSED(C), TransInfo *t) { Editing *ed = SEQ_editing_get(t->scene); const SpaceSeq *sseq = t->area->spacedata.first; @@ -173,25 +173,25 @@ static bool autokeyframe_sequencer_image(bContext *C, bool changed = false; if (do_rot) { prop = RNA_struct_find_property(&ptr, "rotation"); - changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false); } if (do_loc) { prop = RNA_struct_find_property(&ptr, "offset_x"); - changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false); prop = RNA_struct_find_property(&ptr, "offset_y"); - changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false); } if (do_scale) { prop = RNA_struct_find_property(&ptr, "scale_x"); - changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false); prop = RNA_struct_find_property(&ptr, "scale_y"); - changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false); } return changed; } -void recalcData_sequencer_image(TransInfo *t) +static void recalcData_sequencer_image(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); TransData *td = NULL; @@ -247,7 +247,7 @@ void recalcData_sequencer_image(TransInfo *t) } } -void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t) +static void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); @@ -271,3 +271,10 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo * } } } + +TransConvertTypeInfo TransConvertType_SequencerImage = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransSeqImageData, + /* recalcData */ recalcData_sequencer_image, + /* special_aftertrans_update */ special_aftertrans_update__sequencer_image, +}; diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c index d447cd71a40..c0c660289a5 100644 --- a/source/blender/editors/transform/transform_convert_tracking.c +++ b/source/blender/editors/transform/transform_convert_tracking.c @@ -518,7 +518,7 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t) } } -void createTransTrackingData(bContext *C, TransInfo *t) +static void createTransTrackingData(bContext *C, TransInfo *t) { ARegion *region = CTX_wm_region(C); SpaceClip *sc = CTX_wm_space_clip(C); @@ -694,7 +694,7 @@ static void flushTransTracking(TransInfo *t) } } -void recalcData_tracking(TransInfo *t) +static void recalcData_tracking(TransInfo *t) { SpaceClip *sc = t->area->spacedata.first; @@ -747,7 +747,7 @@ void recalcData_tracking(TransInfo *t) /** \name Special After Transform Tracking * \{ */ -void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) +static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) { SpaceClip *sc = t->area->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); @@ -790,3 +790,10 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) } /** \} */ + +TransConvertTypeInfo TransConvertType_Tracking = { + /* flags */ (T_POINTS | T_2D_EDIT), + /* createTransData */ createTransTrackingData, + /* recalcData */ recalcData_tracking, + /* special_aftertrans_update */ special_aftertrans_update__movieclip, +}; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index e45cac36736..56a7d045dfd 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -555,7 +555,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else { /* Release confirms preference should not affect node editor (T69288, T70504). */ - if (ISMOUSE(t->launch_event) && + if (ISMOUSE_BUTTON(t->launch_event) && ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) { /* Global "release confirm" on mouse bindings */ t->flag |= T_RELEASE_CONFIRM; diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 83f1bd35f81..d8da7a11d28 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -292,6 +292,9 @@ void constraintTransLim(const TransInfo *t, TransData *td) continue; } + /* Initialize the custom space for use in calculating the matrices. */ + BKE_constraint_custom_object_space_init(&cob, con); + /* get constraint targets if needed */ BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime); @@ -549,18 +552,14 @@ void ElementRotation_ex(const TransInfo *t, mul_m3_m3m3(totmat, mat, td->mtx); mul_m3_m3m3(smat, td->smtx, totmat); - /* apply gpencil falloff */ + /* Apply gpencil falloff. */ if (t->options & CTX_GPENCIL_STROKES) { bGPDstroke *gps = (bGPDstroke *)td->extra; - float sx = smat[0][0]; - float sy = smat[1][1]; - float sz = smat[2][2]; - - mul_m3_fl(smat, gps->runtime.multi_frame_falloff); - /* fix scale */ - smat[0][0] = sx; - smat[1][1] = sy; - smat[2][2] = sz; + if (gps->runtime.multi_frame_falloff != 1.0f) { + float ident_mat[3][3]; + unit_m3(ident_mat); + interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff); + } } sub_v3_v3v3(vec, td->iloc, center); @@ -945,7 +944,11 @@ void ElementResize(const TransInfo *t, if (td->ext && td->ext->size) { float fsize[3]; - if (ELEM(t->data_type, TC_SCULPT, TC_OBJECT, TC_OBJECT_TEXSPACE, TC_POSE)) { + if (ELEM(t->data_type, + &TransConvertType_Sculpt, + &TransConvertType_Object, + &TransConvertType_ObjectTexSpace, + &TransConvertType_Pose)) { float obsizemat[3][3]; /* Reorient the size mat to fit the oriented object. */ mul_m3_m3m3(obsizemat, tmat, td->axismtx); @@ -1205,7 +1208,7 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) break; } - if (t->data_type == TC_MESH_VERTS) { + if (t->data_type == &TransConvertType_Mesh) { /* Init Custom Data correction. * Ideally this should be called when creating the TransData. */ transform_convert_mesh_customdatacorrect_init(t); diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index aa4d608de04..f7f9e14b8ac 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -64,10 +64,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) if (td->val) { *td->val = td->ival * ratio; /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } + *td->val = interpf(*td->val, td->ival, td->factor); + CLAMP_MIN(*td->val, 0.0f); } } } @@ -93,10 +91,6 @@ void initCurveShrinkFatten(TransInfo *t) t->num.unit_sys = t->scene->unit.system; t->num.unit_type[0] = B_UNIT_NONE; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; -#endif - t->flag |= T_NO_CONSTRAINT; } diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c index 987d8396907..e96e74b596c 100644 --- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c +++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c @@ -44,16 +44,11 @@ static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t), TransData *td, const float weight) { - if (td->val == NULL) { + if (td->loc == NULL) { return; } - *td->val = td->ival + weight * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } + *td->loc = td->iloc[0] + weight * td->factor; + CLAMP(*td->loc, 0.0f, 1.0f); } static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v, diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index f1acc2a4c9a..1a3ccf30387 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -44,17 +44,12 @@ static void transdata_elem_crease(const TransInfo *UNUSED(t), TransData *td, const float crease) { - if (td->val == NULL) { + if (td->loc == NULL) { return; } - *td->val = td->ival + crease * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } + *td->loc = td->iloc[0] + crease * td->factor; + CLAMP(*td->loc, 0.0f, 1.0f); } static void transdata_elem_crease_fn(void *__restrict iter_data_v, diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index 2327aa4e9c4..8d790b4699b 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -84,7 +84,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) transform_snap_increment(t, &angle); - applySnapping(t, &angle); + applySnappingAsGroup(t, &angle); applyNumInput(&t->num, &angle); diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index 9a732562709..5ca1fdf75c6 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -87,7 +87,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2])) } else { copy_v2_v2(values_final, t->values); - applySnapping(t, values_final); + applySnappingAsGroup(t, values_final); transform_convert_sequencer_channel_clamp(t, values_final); if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index b8e9a0d1a4d..a3c49d2362f 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1292,7 +1292,7 @@ static void edge_slide_snap_apply(TransInfo *t, float *value) side_index = t_snap >= t_mid; } - if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) { float co_dir[3]; sub_v3_v3v3(co_dir, co_dest[side_index], co_orig); normalize_v3(co_dir); @@ -1444,7 +1444,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0] + t->values_modal_offset[0]; - applySnapping(t, &final); + applySnappingAsGroup(t, &final); if (!validSnap(t)) { transform_snap_increment(t, &final); } diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c index 83dce17d104..8b9431b65ea 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.c +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -74,7 +74,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2])) if (td->val) { *td->val = td->ival * ratio; /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + *td->val = interpf(*td->val, td->ival, td->factor); CLAMP(*td->val, 0.0f, 1.0f); } } diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c index 796d5c7ae9c..d8ec7d4ff50 100644 --- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -74,7 +74,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) if (td->val) { *td->val = td->ival * ratio; /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + *td->val = interpf(*td->val, td->ival, td->factor); if (*td->val <= 0.0f) { *td->val = 0.001f; } diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c index 19a3deade63..e2ccf61796b 100644 --- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -90,7 +90,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + *td->val = interpf(*td->val, td->ival, td->factor); if (*td->val <= 0.0f) { *td->val = 0.001f; } diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index ffae651e4aa..1ccda96fecb 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -11,6 +11,7 @@ #include "BLI_task.h" #include "BKE_context.h" +#include "BKE_image.h" #include "BKE_unit.h" #include "ED_screen.h" @@ -84,6 +85,103 @@ static void ApplySnapResize(TransInfo *t, float vec[3]) } } +/** + * Find the correction for the scaling factor when "Constrain to Bounds" is active. + * \param numerator: How far the UV boundary (unit square) is from the origin of the scale. + * \param denominator: How far the AABB is from the origin of the scale. + * \param scale: Scale parameter to update. + */ +static void constrain_scale_to_boundary(const float numerator, + const float denominator, + float *scale) +{ + if (denominator == 0.0f) { + /* The origin of the scale is on the edge of the boundary. */ + if (numerator < 0.0f) { + /* Negative scale will wrap around and put us outside the boundary. */ + *scale = 0.0f; /* Hold at the boundary instead. */ + } + return; /* Nothing else we can do without more info. */ + } + + const float correction = numerator / denominator; + if (correction < 0.0f || !isfinite(correction)) { + /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */ + return; + } + + if (denominator < 0.0f) { + /* Scale origin is outside boundary, only make scale bigger. */ + if (*scale < correction) { + *scale = correction; + } + return; + } + + /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */ + if (*scale > correction) { + *scale = correction; + } +} + +static bool clip_uv_transform_resize(TransInfo *t, float vec[2]) +{ + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + BKE_image_find_nearest_tile_with_offset(image, t->center_global, base_offset); + } + + /* Assume no change is required. */ + float scale = 1.0f; + + /* Are we scaling U and V together, or just one axis? */ + const bool adjust_u = !(t->con.mode & CON_AXIS1); + const bool adjust_v = !(t->con.mode & CON_AXIS0); + const bool use_local_center = transdata_check_local_center(t, t->around); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) { + + /* Get scale origin. */ + const float *scale_origin = use_local_center ? td->center : t->center_global; + + /* Alias td->loc as min and max just in case we need to optimize later. */ + const float *min = td->loc; + const float *max = td->loc; + + if (adjust_u) { + /* Update U against the left border. */ + constrain_scale_to_boundary( + scale_origin[0] - base_offset[0], scale_origin[0] - min[0], &scale); + + /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */ + constrain_scale_to_boundary( + base_offset[0] + t->aspect[0] - scale_origin[0], max[0] - scale_origin[0], &scale); + } + + /* Do the same for the V co-ordinate. */ + if (adjust_v) { + constrain_scale_to_boundary( + scale_origin[1] - base_offset[1], scale_origin[1] - min[1], &scale); + + constrain_scale_to_boundary( + base_offset[1] + t->aspect[1] - scale_origin[1], max[1] - scale_origin[1], &scale); + } + } + } + vec[0] *= scale; + vec[1] *= scale; + return scale != 1.0f; +} + static void applyResize(TransInfo *t, const int UNUSED(mval[2])) { float mat[3][3]; @@ -105,7 +203,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) constraintNumInput(t, t->values_final); } - applySnapping(t, t->values_final); + applySnappingAsGroup(t, t->values_final); } size_to_mat3(mat, t->values_final); @@ -157,7 +255,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) } /* Evil hack - redo resize if clipping needed. */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) { + if (t->flag & T_CLIP_UV && clip_uv_transform_resize(t, t->values_final)) { size_to_mat3(mat, t->values_final); if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index f75c65448df..a7207b36578 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -305,7 +305,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) final = large_rotation_limit(final); } else { - applySnapping(t, &final); + applySnappingAsGroup(t, &final); if (!(activeSnap(t) && validSnap(t))) { transform_snap_increment(t, &final); } diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index 8099449ec23..bdbb66b72f4 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -99,7 +99,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) constraintNumInput(t, t->values_final); } - applySnapping(t, t->values_final); + applySnappingAsGroup(t, t->values_final); } size_to_mat3(mat_final, t->values_final); diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c index 4130f6dc034..1474bc4591a 100644 --- a/source/blender/editors/transform/transform_mode_timescale.c +++ b/source/blender/editors/transform/transform_mode_timescale.c @@ -59,7 +59,7 @@ static void applyTimeScaleValue(TransInfo *t, float value) * (this is only valid when not in NLA) */ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - float startx = CFRA; + float startx = scene->r.cfra; float fac = value; /* take proportional editing into account */ @@ -107,7 +107,7 @@ void initTimeScale(TransInfo *t) t->mode = TFM_TIME_SCALE; t->transform = applyTimeScale; - /* recalculate center2d to use CFRA and mouse Y, since that's + /* recalculate center2d to use scene->r.cfra and mouse Y, since that's * what is used in time scale */ if ((t->flag & T_OVERRIDE_CENTER) == 0) { t->center_global[0] = t->scene->r.cfra; diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 3c6b6ea4117..04a41814b53 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -16,6 +16,7 @@ #include "BLI_task.h" #include "BKE_context.h" +#include "BKE_image.h" #include "BKE_report.h" #include "BKE_unit.h" @@ -434,6 +435,54 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) custom_data->prev.rotate_mode = rotate_mode; } +static bool clip_uv_transform_translation(TransInfo *t, float vec[2]) +{ + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + BKE_image_find_nearest_tile_with_offset(image, t->center_global, base_offset); + } + + float min[2], max[2]; + min[0] = min[1] = FLT_MAX; + max[0] = max[1] = -FLT_MAX; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) { + minmax_v2v2_v2(min, max, td->loc); + } + } + + bool result = false; + if (min[0] < base_offset[0]) { + vec[0] += base_offset[0] - min[0]; + result = true; + } + else if (max[0] > base_offset[0] + t->aspect[0]) { + vec[0] -= max[0] - base_offset[0] - t->aspect[0]; + result = true; + } + + if (min[1] < base_offset[1]) { + vec[1] += base_offset[1] - min[1]; + result = true; + } + else if (max[1] > base_offset[1] + t->aspect[1]) { + vec[1] -= max[1] - base_offset[1] - t->aspect[1]; + result = true; + } + + return result; +} + static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; @@ -470,7 +519,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) } t->tsnap.snapElem = SCE_SNAP_MODE_NONE; - applySnapping(t, global_dir); + applySnappingAsGroup(t, global_dir); transform_snap_grid(t, global_dir); if (t->con.mode & CON_APPLY) { @@ -498,7 +547,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) applyTranslationValue(t, global_dir); /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) { + if (t->flag & T_CLIP_UV && clip_uv_transform_translation(t, global_dir)) { applyTranslationValue(t, global_dir); /* In proportional edit it can happen that */ diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 77c5707d814..674ffcf17a8 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -539,7 +539,7 @@ static void vert_slide_snap_apply(TransInfo *t, float *value) getSnapPoint(t, dvec); sub_v3_v3(dvec, t->tsnap.snapTarget); - if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) { float co_dir[3]; sub_v3_v3v3(co_dir, co_curr_3d, co_orig_3d); normalize_v3(co_dir); @@ -568,7 +568,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0] + t->values_modal_offset[0]; - applySnapping(t, &final); + applySnappingAsGroup(t, &final); if (!validSnap(t)) { transform_snap_increment(t, &final); } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index a64eff8f981..7c94241f3e3 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -566,6 +566,17 @@ static bool transform_poll_property(const bContext *UNUSED(C), } } + /* Snapping. */ + { + PropertyRNA *prop_snap = RNA_struct_find_property(op->ptr, "snap"); + if (prop_snap && (prop_snap != prop) && + (RNA_property_boolean_get(op->ptr, prop_snap) == false)) { + if (STRPREFIX(prop_id, "snap") || STRPREFIX(prop_id, "use_snap")) { + return false; + } + } + } + return true; } @@ -644,28 +655,63 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) } if (flags & P_SNAP) { - prop = RNA_def_boolean(ot->srna, "snap", 0, "Use Snapping Options", ""); + prop = RNA_def_boolean(ot->srna, "snap", false, "Use Snapping Options", ""); RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_enum(ot->srna, + "snap_elements", + rna_enum_snap_element_items, + SCE_SNAP_MODE_INCREMENT, + "Snap to Elements", + ""); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + + RNA_def_boolean(ot->srna, "use_snap_project", false, "Project Individual Elements", ""); + if (flags & P_GEO_SNAP) { - /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid - * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is - * geometry to which moved geometry is snapped). Use "Source snap point" and "Point on - * source that will snap to target" for name and description, respectively. */ - prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Target", ""); + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of + * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved + * geometry is snapped). Use "Source snap point" and "Point on source that will snap to + * target" for name and description, respectively. */ + prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Snap With", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* Target selection. */ + prop = RNA_def_boolean(ot->srna, "use_snap_self", true, "Target: Include Active", ""); RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "use_snap_edit", true, "Target: Include Edit", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "use_snap_nonedit", true, "Target: Include Non-Edited", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_boolean( + ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* Face Nearest options */ + prop = RNA_def_boolean( + ot->srna, "use_snap_to_same_target", false, "Snap to Same Target", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int( + ot->srna, "snap_face_nearest_steps", 1, 1, 32767, "Face Nearest Steps", "", 1, 32767); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_float_vector( ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); if (flags & P_ALIGN_SNAP) { - prop = RNA_def_boolean(ot->srna, "snap_align", 0, "Align with Point Normal", ""); + prop = RNA_def_boolean(ot->srna, "snap_align", false, "Align with Point Normal", ""); RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_float_vector( ot->srna, "snap_normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); } } + else { + prop = RNA_def_boolean( + ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + } } if (flags & P_GPENCIL_EDIT) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 649217092aa..9a563aaf473 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -126,8 +126,12 @@ bool activeSnap(const TransInfo *t) ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT); } -bool activeSnap_with_project(const TransInfo *t) +bool activeSnap_SnappingIndividual(const TransInfo *t) { + if (activeSnap(t) && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) { + return true; + } + if (!t->tsnap.project) { return false; } @@ -143,6 +147,27 @@ bool activeSnap_with_project(const TransInfo *t) return true; } +bool activeSnap_SnappingAsGroup(const TransInfo *t) +{ + if (!activeSnap(t)) { + return false; + } + + if (t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST && t->tsnap.project) { + return false; + } + + if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) { + return false; + } + + if (doForceIncrementSnap(t)) { + return false; + } + + return true; +} + bool transformModeUseSnap(const TransInfo *t) { ToolSettings *ts = t->settings; @@ -343,93 +368,157 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event) return status; } -void applyProject(TransInfo *t) +static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td) { - if (!activeSnap_with_project(t)) { - return; + if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) { + return false; + } + + float iloc[3], loc[3], no[3]; + float mval_fl[2]; + + copy_v3_v3(iloc, td->loc); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, iloc); + } + else if (t->options & CTX_OBJECT) { + BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); + copy_v3_v3(iloc, td->ob->obmat[3]); + } + + if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) != + V3D_PROJ_RET_OK) { + return false; + } + + eSnapMode hit = ED_transform_snap_object_project_view3d( + t->tsnap.object_context, + t->depsgraph, + t->region, + t->view, + SCE_SNAP_MODE_FACE_RAYCAST, + &(const struct SnapObjectParams){ + .snap_target_select = t->tsnap.target_select, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, + .use_occlusion_test = false, + .use_backface_culling = t->tsnap.use_backface_culling, + }, + NULL, + mval_fl, + NULL, + 0, + loc, + no); + if (hit != SCE_SNAP_MODE_FACE_RAYCAST) { + return false; } float tvec[3]; - int i; + sub_v3_v3v3(tvec, loc, iloc); - /* XXX FLICKER IN OBJECT MODE */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float iloc[3], loc[3], no[3]; - float mval_fl[2]; - if (td->flag & TD_SKIP) { - continue; - } + mul_m3_v3(td->smtx, tvec); - if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { - continue; - } + add_v3_v3(td->loc, tvec); - copy_v3_v3(iloc, td->loc); - if (tc->use_local_mat) { - mul_m4_v3(tc->mat, iloc); - } - else if (t->options & CTX_OBJECT) { - BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); - } + if (t->tsnap.align && (t->options & CTX_OBJECT)) { + /* handle alignment as well */ + const float *original_normal; + float mat[3][3]; - if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) == - V3D_PROJ_RET_OK) { - eSnapMode hit = ED_transform_snap_object_project_view3d( - t->tsnap.object_context, - t->depsgraph, - t->region, - t->view, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_target_select = t->tsnap.target_select, - .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, - .use_occlusion_test = false, - .use_backface_culling = t->tsnap.use_backface_culling, - }, - mval_fl, - NULL, - 0, - loc, - no); - if (hit != SCE_SNAP_MODE_FACE) { - return; - } + /* In pose mode, we want to align normals with Y axis of bones. */ + original_normal = td->axismtx[2]; -#if 0 - if (tc->use_local_mat) { - mul_m4_v3(tc->imat, loc); - } -#endif + rotation_between_vecs_to_mat3(mat, original_normal, no); + + transform_data_ext_rotate(td, mat, true); + + /* TODO: support constraints for rotation too? see #ElementRotation. */ + } + return true; +} + +static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td) +{ + if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) { + return; + } - sub_v3_v3v3(tvec, loc, iloc); + float init_loc[3]; + float prev_loc[3]; + float snap_loc[3], snap_no[3]; - mul_m3_v3(td->smtx, tvec); + copy_v3_v3(init_loc, td->iloc); + copy_v3_v3(prev_loc, td->loc); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, init_loc); + mul_m4_v3(tc->mat, prev_loc); + } + else if (t->options & CTX_OBJECT) { + BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); + copy_v3_v3(init_loc, td->ob->obmat[3]); + } - add_v3_v3(td->loc, tvec); + eSnapMode hit = ED_transform_snap_object_project_view3d( + t->tsnap.object_context, + t->depsgraph, + t->region, + t->view, + SCE_SNAP_MODE_FACE_NEAREST, + &(const struct SnapObjectParams){ + .snap_target_select = t->tsnap.target_select, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, + .use_occlusion_test = false, + .use_backface_culling = false, + .face_nearest_steps = t->tsnap.face_nearest_steps, + .keep_on_same_target = t->tsnap.flag & SCE_SNAP_KEEP_ON_SAME_OBJECT, + }, + init_loc, + NULL, + prev_loc, + 0, + snap_loc, + snap_no); + + if (hit != SCE_SNAP_MODE_FACE_NEAREST) { + return; + } - if (t->tsnap.align && (t->options & CTX_OBJECT)) { - /* handle alignment as well */ - const float *original_normal; - float mat[3][3]; + float tvec[3]; + sub_v3_v3v3(tvec, snap_loc, prev_loc); + mul_m3_v3(td->smtx, tvec); + add_v3_v3(td->loc, tvec); - /* In pose mode, we want to align normals with Y axis of bones... */ - original_normal = td->axismtx[2]; + /* TODO: support snap alignment similar to #SCE_SNAP_MODE_FACE_RAYCAST? */ +} - rotation_between_vecs_to_mat3(mat, original_normal, no); +void applySnappingIndividual(TransInfo *t) +{ + if (!activeSnap_SnappingIndividual(t)) { + return; + } - transform_data_ext_rotate(td, mat, true); + /* XXX FLICKER IN OBJECT MODE */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (int i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } - /* TODO: support constraints for rotation too? see #ElementRotation. */ - } + if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { + continue; } - } + /* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and + * fallback to face nearest ray-cast does not hit. */ + bool hit = applyFaceProject(t, tc, td); + if (!hit) { + applyFaceNearest(t, tc, td); + } #if 0 /* TODO: support this? */ - constraintTransLim(t, td); + constraintTransLim(t, td); #endif + } } } @@ -483,15 +572,9 @@ void applyGridAbsolute(TransInfo *t) } } -void applySnapping(TransInfo *t, float *vec) +void applySnappingAsGroup(TransInfo *t, float *vec) { - /* Each Trans Data already makes the snap to face */ - if (doForceIncrementSnap(t)) { - return; - } - - if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { - /* A similar snap will be applied to each transdata in `applyProject`. */ + if (!activeSnap_SnappingAsGroup(t)) { return; } @@ -644,70 +727,76 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t) return SCE_SNAP_MODE_INCREMENT; } -static eSnapTargetSelect snap_select_type_get(TransInfo *t) +static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t) { ViewLayer *view_layer = t->view_layer; Base *base_act = view_layer->basact; + + eSnapTargetSelect ret = SCE_SNAP_TARGET_ALL; + + bool use_snap_active = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_ACTIVE) == 0; + bool use_snap_edit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_EDITED) == 0; + bool use_snap_nonedit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_NONEDITED) == 0; + bool use_snap_selectable_only = (t->tsnap.target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0; + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { + if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { + /* Particles edit mode. */ + return ret; + } + + if (use_snap_selectable_only) { + ret |= SCE_SNAP_TARGET_ONLY_SELECTABLE; + } + if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) * TODO: perform self snap in gpencil_strokes. * * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ - return SCE_SNAP_TARGET_ALL; + return ret; } const int obedit_type = t->obedit_type; if (obedit_type != -1) { /* Edit mode */ - if (ELEM(obedit_type, - OB_MESH, - OB_ARMATURE, - OB_CURVES_LEGACY, - OB_SURF, - OB_LATTICE, - OB_MBALL)) { - /* Temporary limited to edit mode meshes, armature, curves, lattice and metaballs. */ - - if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { - /* Exclude editmesh if using proportional edit */ - return SCE_SNAP_TARGET_NOT_EDITED; + if (obedit_type == OB_MESH) { + /* Editing a mesh */ + if ((t->flag & T_PROP_EDIT) != 0) { + /* Exclude editmesh when using proportional edit */ + ret |= SCE_SNAP_TARGET_NOT_EDITED; } - - if (!t->tsnap.snap_self) { - return SCE_SNAP_TARGET_NOT_ACTIVE; + if (!use_snap_active) { + ret |= SCE_SNAP_TARGET_NOT_ACTIVE; + } + if (!use_snap_edit) { + ret |= SCE_SNAP_TARGET_NOT_EDITED; + } + if (!use_snap_nonedit) { + ret |= SCE_SNAP_TARGET_NOT_NONEDITED; } - - return SCE_SNAP_TARGET_NOT_SELECTED; } - - return SCE_SNAP_TARGET_ALL; + else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) { + /* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */ + ret |= SCE_SNAP_TARGET_NOT_SELECTED; + } } - - if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { - /* Particles edit mode. */ - return SCE_SNAP_TARGET_ALL; + else { + /* Object or pose mode. */ + ret |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE; } - - /* Object or pose mode. */ - return SCE_SNAP_TARGET_NOT_SELECTED; } - - if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - return SCE_SNAP_TARGET_NOT_SELECTED; + else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { + ret |= SCE_SNAP_TARGET_NOT_SELECTED; } - return SCE_SNAP_TARGET_ALL; + return ret; } static void initSnappingMode(TransInfo *t) { - ToolSettings *ts = t->settings; - t->tsnap.mode = snap_mode_from_spacetype(t); - t->tsnap.target_select = snap_select_type_get(t); - - if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { + if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) { /* Force project off when not supported. */ t->tsnap.project = false; } @@ -724,7 +813,7 @@ static void initSnappingMode(TransInfo *t) t->tsnap.use_backface_culling = snap_use_backface_culling(t); t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0); - if (t->data_type == TC_MESH_VERTS) { + if (t->data_type == &TransConvertType_Mesh) { /* Ignore elements being transformed. */ ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, @@ -753,9 +842,14 @@ static void initSnappingMode(TransInfo *t) void initSnapping(TransInfo *t, wmOperator *op) { + ToolSettings *ts = t->settings; + eSnapSourceSelect snap_source = ts->snap_target; + resetSnapping(t); + t->tsnap.mode = snap_mode_from_spacetype(t); t->tsnap.flag = snap_flag_from_spacetype(t); - eSnapSourceSelect snap_source = t->settings->snap_target; + t->tsnap.target_select = snap_target_select_from_spacetype(t); + t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1); /* if snap property exists */ PropertyRNA *prop; @@ -764,11 +858,16 @@ void initSnapping(TransInfo *t, wmOperator *op) if (RNA_property_boolean_get(op->ptr, prop)) { t->modifiers |= MOD_SNAP; + if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) && + RNA_property_is_set(op->ptr, prop)) { + t->tsnap.mode = RNA_property_enum_get(op->ptr, prop); + } + + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of + * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved + * geometry is snapped). */ if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) && RNA_property_is_set(op->ptr, prop)) { - /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid - * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is - * geometry to which moved geometry is snapped). */ snap_source = RNA_property_enum_get(op->ptr, prop); } @@ -791,9 +890,33 @@ void initSnapping(TransInfo *t, wmOperator *op) t->tsnap.project = RNA_property_boolean_get(op->ptr, prop); } + /* use_snap_self is misnamed and should be use_snap_active */ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) && RNA_property_is_set(op->ptr, prop)) { - t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop); + SET_FLAG_FROM_TEST(t->tsnap.target_select, + !RNA_property_boolean_get(op->ptr, prop), + SCE_SNAP_TARGET_NOT_ACTIVE); + } + + if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) && + RNA_property_is_set(op->ptr, prop)) { + SET_FLAG_FROM_TEST(t->tsnap.target_select, + !RNA_property_boolean_get(op->ptr, prop), + SCE_SNAP_TARGET_NOT_EDITED); + } + + if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) && + RNA_property_is_set(op->ptr, prop)) { + SET_FLAG_FROM_TEST(t->tsnap.target_select, + !RNA_property_boolean_get(op->ptr, prop), + SCE_SNAP_TARGET_NOT_NONEDITED); + } + + if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) && + RNA_property_is_set(op->ptr, prop)) { + SET_FLAG_FROM_TEST(t->tsnap.target_select, + RNA_property_boolean_get(op->ptr, prop), + SCE_SNAP_TARGET_ONLY_SELECTABLE); } } } @@ -805,8 +928,19 @@ void initSnapping(TransInfo *t, wmOperator *op) t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0); t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); - t->tsnap.snap_self = !((t->tsnap.flag & SCE_SNAP_NO_SELF) != 0); t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); + SET_FLAG_FROM_TEST(t->tsnap.target_select, + (ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE), + SCE_SNAP_TARGET_NOT_ACTIVE); + SET_FLAG_FROM_TEST(t->tsnap.target_select, + !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED), + SCE_SNAP_TARGET_NOT_EDITED); + SET_FLAG_FROM_TEST(t->tsnap.target_select, + !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED), + SCE_SNAP_TARGET_NOT_NONEDITED); + SET_FLAG_FROM_TEST(t->tsnap.target_select, + (ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE), + SCE_SNAP_TARGET_ONLY_SELECTABLE); } t->tsnap.source_select = snap_source; @@ -991,8 +1125,8 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) found = (snap_elem != SCE_SNAP_MODE_NONE); } if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { - found = peelObjectsTransform( - t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL); + bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0; + found = peelObjectsTransform(t, mval, use_peel, loc, no, NULL); if (found) { snap_elem = SCE_SNAP_MODE_VOLUME; @@ -1026,7 +1160,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec)) objects, objects_len, t->mval, - t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED, + t->tsnap.target_select & SCE_SNAP_TARGET_NOT_SELECTED, &dist_sq, t->tsnap.snapPoint)) { t->tsnap.snapPoint[0] *= t->aspect[0]; @@ -1118,7 +1252,7 @@ static void snap_target_grid_ensure(TransInfo *t) { /* Only need to calculate once. */ if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { - if (t->data_type == TC_CURSOR_VIEW3D) { + if (t->data_type == &TransConvertType_Cursor3D) { /* Use a fallback when transforming the cursor. * In this case the center is _not_ derived from the cursor which is being transformed. */ copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); @@ -1321,9 +1455,10 @@ eSnapMode snapObjectsTransform( &(const struct SnapObjectParams){ .snap_target_select = t->tsnap.target_select, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, - .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE, + .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST, .use_backface_culling = t->tsnap.use_backface_culling, }, + NULL, mval, target, dist_px, @@ -1423,7 +1558,7 @@ bool peelObjectsTransform(TransInfo *t, static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select) { /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ - return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) || + return (((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && !(node->flag & NODE_SELECT)) || (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) && (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin && node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin); diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 6db027df067..3672e76c778 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -40,15 +40,16 @@ float transform_snap_increment_get(const TransInfo *t); bool transform_snap_grid(TransInfo *t, float *val); bool activeSnap(const TransInfo *t); -bool activeSnap_with_project(const TransInfo *t); +bool activeSnap_SnappingIndividual(const TransInfo *t); +bool activeSnap_SnappingAsGroup(const TransInfo *t); bool validSnap(const TransInfo *t); void initSnapping(struct TransInfo *t, struct wmOperator *op); void freeSnapping(struct TransInfo *t); -void applyProject(TransInfo *t); +void applySnappingIndividual(TransInfo *t); void applyGridAbsolute(TransInfo *t); -void applySnapping(TransInfo *t, float *vec); +void applySnappingAsGroup(TransInfo *t, float *vec); void resetSnapping(TransInfo *t); eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event); void drawSnapping(const struct bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index bd3d29fac8a..479214ee2d3 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -405,6 +405,62 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, return sod; } +static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx, + Object *ob_eval, + const Mesh *me_eval, + bool use_hide) +{ + SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); + return &sod->treedata_mesh; +} + +static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx, + Object *ob_eval, + BMEditMesh *em) +{ + SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em); + + BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh; + + if (treedata->tree == nullptr) { + /* Operators only update the editmesh looptris of the original mesh. */ + BLI_assert(sod->treedata_editmesh.em == + BKE_editmesh_from_object(DEG_get_original_object(ob_eval))); + em = sod->treedata_editmesh.em; + + if (sctx->callbacks.edit_mesh.test_face_fn) { + BMesh *bm = em->bm; + BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri); + + BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); + int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + bm, + elem_mask, + sctx->callbacks.edit_mesh.test_face_fn, + sctx->callbacks.edit_mesh.user_data); + + bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6); + + MEM_freeN(elem_mask); + } + else { + /* Only cache if BVH-tree is created without a mask. + * This helps keep a standardized BVH-tree in cache. */ + BKE_bvhtree_from_editmesh_get(treedata, + em, + 4, + BVHTREE_FROM_EM_LOOPTRI, + &sod->mesh_runtime->bvh_cache, + static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex)); + } + } + if (treedata == nullptr || treedata->tree == nullptr) { + return nullptr; + } + + return treedata; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -419,16 +475,16 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx, void *data); static bool snap_object_is_snappable(const SnapObjectContext *sctx, - const eSnapTargetSelect snap_select, + const eSnapTargetSelect snap_target_select, const Base *base_act, - const Base *base, - const bool is_in_object_mode) + const Base *base) { if (!BASE_VISIBLE(sctx->runtime.v3d, base)) { return false; } - if ((snap_select == SCE_SNAP_TARGET_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { + if ((snap_target_select == SCE_SNAP_TARGET_ALL) || + (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { return true; } @@ -436,25 +492,37 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, return false; } - if (snap_select == SCE_SNAP_TARGET_NOT_ACTIVE) { - return base_act != base; - } + /* Get attributes of potential target. */ + const bool is_active = (base_act == base); + const bool is_selected = (base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL); + const bool is_edited = (base->object->mode == OB_MODE_EDIT); + const bool is_selectable = (base->flag & BASE_SELECTABLE); + /* Get attributes of state. */ + const bool is_in_object_mode = (base_act == NULL) || (base_act->object->mode == OB_MODE_OBJECT); - if (snap_select == SCE_SNAP_TARGET_NOT_EDITED) { - return base->object->mode != OB_MODE_EDIT; + if (is_in_object_mode) { + /* Handle target selection options that make sense for object mode. */ + if ((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && is_selected) { + /* What is selectable or not is part of the object and depends on the mode. */ + return false; + } } - - if (snap_select == SCE_SNAP_TARGET_NOT_SELECTED) { - if (is_in_object_mode) { - return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)); + else { + /* Handle target selection options that make sense for edit/pose mode. */ + if ((snap_target_select & SCE_SNAP_TARGET_NOT_ACTIVE) && is_active) { + return false; + } + if ((snap_target_select & SCE_SNAP_TARGET_NOT_EDITED) && is_edited && !is_active) { + /* Base is edited, but not active. */ + return false; + } + if ((snap_target_select & SCE_SNAP_TARGET_NOT_NONEDITED) && !is_edited) { + return false; } - - /* What is selectable or not is part of the object and depends on the mode. */ - return true; } - if (snap_select == SCE_SNAP_TARGET_ONLY_SELECTABLE) { - return (base->flag & BASE_SELECTABLE) != 0; + if ((snap_target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) && !is_selectable) { + return false; } return true; @@ -470,11 +538,10 @@ static void iter_snap_objects(SnapObjectContext *sctx, { ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph); const eSnapTargetSelect snap_target_select = params->snap_target_select; - Base *base_act = view_layer->basact; - const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT; + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base, is_in_object_mode)) { + if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base)) { continue; } @@ -850,40 +917,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx, len_diff = 0.0f; } - BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh; - - if (treedata->tree == nullptr) { - em = sod->treedata_editmesh.em; - - if (sctx->callbacks.edit_mesh.test_face_fn) { - BMesh *bm = em->bm; - BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri); - - BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); - int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( - bm, - elem_mask, - sctx->callbacks.edit_mesh.test_face_fn, - sctx->callbacks.edit_mesh.user_data); - - bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6); - - MEM_freeN(elem_mask); - } - else { - /* Only cache if bvhtree is created without a mask. - * This helps keep a standardized bvhtree in cache. */ - BKE_bvhtree_from_editmesh_get(treedata, - em, - 4, - BVHTREE_FROM_EM_LOOPTRI, - &sod->mesh_runtime->bvh_cache, - static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex)); - } - - if (treedata->tree == nullptr) { - return retval; - } + BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em); + if (treedata == nullptr) { + return retval; } float timat[3][3]; /* transpose inverse matrix for normals */ @@ -1098,7 +1134,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * \param r_loc: Hit location. * \param r_no: Hit normal (optional). * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`). + * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). @@ -1150,6 +1186,324 @@ static bool raycastObjects(SnapObjectContext *sctx, /** \} */ /* -------------------------------------------------------------------- */ +/** \name Surface Snap Funcs + * \{ */ + +struct NearestWorldObjUserData { + const float *init_co; + const float *curr_co; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + float r_dist_sq; + Object **r_ob; + float (*r_obmat)[4]; + ListBase *r_hit_list; + bool ret; +}; + +static void nearest_world_tree_co(BVHTree *tree, + BVHTree_NearestPointCallback nearest_cb, + void *treedata, + float co[3], + float r_co[3], + float r_no[3], + int *r_index, + float *r_dist_sq) +{ + BVHTreeNearest nearest = {}; + nearest.index = -1; + copy_v3_fl(nearest.co, FLT_MAX); + nearest.dist_sq = FLT_MAX; + + BLI_bvhtree_find_nearest(tree, co, &nearest, nearest_cb, treedata); + + if (r_co) { + copy_v3_v3(r_co, nearest.co); + } + if (r_no) { + copy_v3_v3(r_no, nearest.no); + } + if (r_index) { + *r_index = nearest.index; + } + if (r_dist_sq) { + float diff[3]; + sub_v3_v3v3(diff, co, nearest.co); + *r_dist_sq = len_squared_v3(diff); + } +} + +static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx), + const struct SnapObjectParams *params, + BVHTree *tree, + BVHTree_NearestPointCallback nearest_cb, + void *treedata, + const float (*obmat)[4], + const float init_co[3], + const float curr_co[3], + float *r_dist_sq, + float *r_loc, + float *r_no, + int *r_index) +{ + if (curr_co == nullptr || init_co == nullptr) { + /* No location to work with, so just return. */ + return false; + } + + float imat[4][4]; + invert_m4_m4(imat, obmat); + + float timat[3][3]; /* transpose inverse matrix for normals */ + transpose_m3_m4(timat, imat); + + /* compute offset between init co and prev co in local space */ + float init_co_local[3], curr_co_local[3]; + float delta_local[3]; + mul_v3_m4v3(init_co_local, imat, init_co); + mul_v3_m4v3(curr_co_local, imat, curr_co); + sub_v3_v3v3(delta_local, curr_co_local, init_co_local); + + float dist_sq; + if (params->keep_on_same_target) { + nearest_world_tree_co( + tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq); + } + else { + /* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain + * the answer. We could return immediately after updating r_loc, r_no, r_index, but that would + * also complicate the code. Foregoing slight optimization for code clarity. */ + nearest_world_tree_co( + tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq); + } + if (*r_dist_sq <= dist_sq) { + return false; + } + *r_dist_sq = dist_sq; + + /* scale to make `snap_face_nearest_steps` steps */ + float step_scale_factor = 1.0f / max_ff(1.0f, (float)params->face_nearest_steps); + mul_v3_fl(delta_local, step_scale_factor); + + float co_local[3]; + float no_local[3]; + int index; + + copy_v3_v3(co_local, init_co_local); + + for (int i = 0; i < params->face_nearest_steps; i++) { + add_v3_v3(co_local, delta_local); + nearest_world_tree_co( + tree, nearest_cb, treedata, co_local, co_local, no_local, &index, nullptr); + } + + mul_v3_m4v3(r_loc, obmat, co_local); + + if (r_no) { + mul_v3_m3v3(r_no, timat, no_local); + normalize_v3(r_no); + } + + if (r_index) { + *r_index = index; + } + + return true; +} + +static bool nearest_world_mesh(SnapObjectContext *sctx, + const struct SnapObjectParams *params, + Object *ob_eval, + const Mesh *me_eval, + const float (*obmat)[4], + bool use_hide, + const float init_co[3], + const float curr_co[3], + float *r_dist_sq, + float *r_loc, + float *r_no, + int *r_index) +{ + BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide); + if (treedata == nullptr || treedata->tree == nullptr) { + return false; + } + + return nearest_world_tree(sctx, + params, + treedata->tree, + treedata->nearest_callback, + treedata, + obmat, + init_co, + curr_co, + r_dist_sq, + r_loc, + r_no, + r_index); +} + +static bool nearest_world_editmesh(SnapObjectContext *sctx, + const struct SnapObjectParams *params, + Object *ob_eval, + BMEditMesh *em, + const float (*obmat)[4], + const float init_co[3], + const float curr_co[3], + float *r_dist_sq, + float *r_loc, + float *r_no, + int *r_index) +{ + BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em); + if (treedata == nullptr || treedata->tree == nullptr) { + return false; + } + + return nearest_world_tree(sctx, + params, + treedata->tree, + treedata->nearest_callback, + treedata, + obmat, + init_co, + curr_co, + r_dist_sq, + r_loc, + r_no, + r_index); +} +static void nearest_world_object_fn(SnapObjectContext *sctx, + const struct SnapObjectParams *params, + Object *ob_eval, + const float obmat[4][4], + bool is_object_active, + void *data) +{ + struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data); + + bool retval = false; + switch (ob_eval->type) { + case OB_MESH: { + const eSnapEditType edit_mode_type = params->edit_mode_type; + bool use_hide = false; + const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); + if (me_eval) { + retval = nearest_world_mesh(sctx, + params, + ob_eval, + me_eval, + obmat, + use_hide, + dt->init_co, + dt->curr_co, + &dt->r_dist_sq, + dt->r_loc, + dt->r_no, + dt->r_index); + } + else { + BMEditMesh *em = BKE_editmesh_from_object(ob_eval); + BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)), + "Make sure there is only one pointer for looptris"); + retval = nearest_world_editmesh(sctx, + params, + ob_eval, + em, + obmat, + dt->init_co, + dt->curr_co, + &dt->r_dist_sq, + dt->r_loc, + dt->r_no, + dt->r_index); + } + break; + } + case OB_CURVES_LEGACY: + case OB_SURF: + case OB_FONT: + if (!is_object_active) { + const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); + if (me_eval) { + retval = nearest_world_mesh(sctx, + params, + ob_eval, + me_eval, + obmat, + false, + dt->init_co, + dt->curr_co, + &dt->r_dist_sq, + dt->r_loc, + dt->r_no, + dt->r_index); + } + } + break; + } + + if (retval) { + if (dt->r_ob) { + *dt->r_ob = ob_eval; + } + if (dt->r_obmat) { + copy_m4_m4(dt->r_obmat, obmat); + } + dt->ret = true; + } +} + +/** + * Main Nearest World Surface Function + * =================================== + * + * Walks through all objects in the scene to find the nearest location on target surface. + * + * \param sctx: Snap context to store data. + * \param params: Settings for snapping. + * \param init_co: Initial location of source point. + * \param prev_co: Current location of source point after transformation but before snapping. + * + * Output Args + * ----------- + * + * \param r_loc: Location of nearest point on target surface. + * \param r_no: Normal of nearest point on target surface. + * \param r_index: Index of nearest polygon on target surface. + * \param r_ob: Nearest target object. + * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances). + */ +static bool nearestWorldObjects(SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float init_co[3], + const float curr_co[3], + float *r_loc /* NOLINT */, + float *r_no /* NOLINT */, + int *r_index /* NOLINT */, + Object **r_ob, + float r_obmat[4][4]) +{ + NearestWorldObjUserData data = {}; + data.init_co = init_co; + data.curr_co = curr_co; + data.r_loc = r_loc; + data.r_no = r_no; + data.r_index = r_index; + data.r_dist_sq = FLT_MAX; + data.r_ob = r_ob; + data.r_obmat = r_obmat; + data.ret = false; + + iter_snap_objects(sctx, params, nearest_world_object_fn, &data); + return data.ret; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Snap Nearest utilities * \{ */ @@ -1842,7 +2196,8 @@ static eSnapMode snapArmature(SnapObjectContext *sctx, { eSnapMode retval = SCE_SNAP_MODE_NONE; - if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */ + if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE_RAYCAST) { + /* Currently only edge and vert */ return retval; } @@ -2268,7 +2623,7 @@ static eSnapMode snapCamera(const SnapObjectContext *sctx, if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { BKE_tracking_camera_get_reconstructed_interpolate( - tracking, tracking_object, CFRA, reconstructed_camera_mat); + tracking, tracking_object, scene->r.cfra, reconstructed_camera_mat); invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat); } @@ -2328,7 +2683,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, float r_no[3], int *r_index) { - BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE); + BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST); if (me_eval->totvert == 0) { return SCE_SNAP_MODE_NONE; } @@ -2506,9 +2861,9 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, float r_no[3], int *r_index) { - BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE); + BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST); - if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) { + if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE_RAYCAST) == SCE_SNAP_MODE_VERTEX) { if (em->bm->totvert == 0) { return SCE_SNAP_MODE_NONE; } @@ -2811,7 +3166,7 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_loc: Hit location. * \param r_no: Hit normal (optional). * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`). + * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). */ @@ -3014,6 +3369,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont const View3D *v3d, const eSnapMode snap_to_flag, const SnapObjectParams *params, + const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, @@ -3045,11 +3401,36 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d); - if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) { + /* Note: if both face raycast and face nearest are enabled, first find result of nearest, then + * override with raycast. */ + if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) { + has_hit = nearestWorldObjects( + sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat); + + if (has_hit) { + retval = SCE_SNAP_MODE_FACE_NEAREST; + + copy_v3_v3(r_loc, loc); + if (r_no) { + copy_v3_v3(r_no, no); + } + if (r_ob) { + *r_ob = ob_eval; + } + if (r_obmat) { + copy_m4_m4(r_obmat, obmat); + } + if (r_index) { + *r_index = index; + } + } + } + + if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) { float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_clipped_ex( depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) { - return SCE_SNAP_MODE_NONE; + return retval; } float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; @@ -3071,8 +3452,8 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont copy_v3_v3(r_face_nor, no); } - if ((snap_to_flag & SCE_SNAP_MODE_FACE)) { - retval = SCE_SNAP_MODE_FACE; + if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) { + retval = SCE_SNAP_MODE_FACE_RAYCAST; copy_v3_v3(r_loc, loc); if (r_no) { @@ -3193,6 +3574,7 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, const View3D *v3d, const eSnapMode snap_to, const SnapObjectParams *params, + const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, @@ -3209,6 +3591,7 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, v3d, snap_to, params, + init_co, mval, prev_co, dist_px, @@ -3226,6 +3609,7 @@ eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, const View3D *v3d, const eSnapMode snap_to, const SnapObjectParams *params, + const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, @@ -3238,6 +3622,7 @@ eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, v3d, snap_to, params, + init_co, mval, prev_co, dist_px, diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index 7972410ad67..06d9bb05206 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -28,6 +28,7 @@ #include "SEQ_time.h" #include "transform.h" +#include "transform_convert.h" #include "transform_snap.h" typedef struct TransSeqSnapData { @@ -191,7 +192,7 @@ static void seq_snap_target_points_build(Scene *scene, int i = 0; if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) { - snap_data->target_snap_points[i] = CFRA; + snap_data->target_snap_points[i] = scene->r.cfra; i++; } @@ -244,7 +245,7 @@ static int seq_snap_threshold_get_frame_distance(const TransInfo *t) TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t) { - if (t->data_type == TC_SEQ_IMAGE_DATA) { + if (t->data_type == &TransConvertType_SequencerImage) { return NULL; } @@ -375,7 +376,7 @@ bool ED_transform_snap_sequencer_to_closest_strip_calc(Scene *scene, t.scene = scene; t.region = region; t.values[0] = 0; - t.data_type = TC_SEQ_DATA; + t.data_type = &TransConvertType_Sequencer; t.tsnap.mode = SEQ_tool_settings_snap_mode_get(scene); *r_snap_distance = transform_snap_sequencer_to_closest_strip_ex(&t, frame_1, frame_2); |