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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2020-05-30 11:34:11 +0300
committerYimingWu <xp8110@outlook.com>2020-05-30 11:34:11 +0300
commit3b52dfe549f0c2fca7e0cd499b85fb098e9b4da9 (patch)
tree668b6b25da0efdb87058b197084094181fb0c09f /source/blender/editors
parentcd54abd2c1316136753f7bbe227bd762a5f9e7d9 (diff)
parent2ee94c954d6700a45fde320f330964bcf1888545 (diff)
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
# Conflicts: # release/datafiles/locale # release/scripts/addons # source/blender/blenkernel/intern/lib_query.c
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/armature/armature_relations.c3
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c95
-rw-r--r--source/blender/editors/curve/editcurve.c4
-rw-r--r--source/blender/editors/curve/editcurve_add.c4
-rw-r--r--source/blender/editors/curve/editcurve_query.c13
-rw-r--r--source/blender/editors/curve/editcurve_select.c11
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c564
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c31
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h7
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c24
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c154
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h38
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/ED_object.h2
-rw-r--r--source/blender/editors/include/ED_outliner.h1
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_transform.h2
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h7
-rw-r--r--source/blender/editors/include/ED_uvedit.h17
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_interface.h23
-rw-r--r--source/blender/editors/interface/CMakeLists.txt2
-rw-r--r--source/blender/editors/interface/interface_align.c10
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c11
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c5
-rw-r--r--source/blender/editors/interface/interface_handlers.c9
-rw-r--r--source/blender/editors/interface/interface_intern.h2
-rw-r--r--source/blender/editors/interface/interface_panel.c501
-rw-r--r--source/blender/editors/interface/interface_region_hud.c5
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c43
-rw-r--r--source/blender/editors/interface/interface_templates.c15
-rw-r--r--source/blender/editors/interface/interface_widgets.c26
-rw-r--r--source/blender/editors/interface/view2d_draw.c15
-rw-r--r--source/blender/editors/mesh/editmesh_add.c113
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c3
-rw-r--r--source/blender/editors/object/object_add.c81
-rw-r--r--source/blender/editors/object/object_bake_api.c26
-rw-r--r--source/blender/editors/object/object_edit.c9
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_volume.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c7
-rw-r--r--source/blender/editors/physics/physics_fluid.c9
-rw-r--r--source/blender/editors/render/render_internal.c36
-rw-r--r--source/blender/editors/render/render_opengl.c2
-rw-r--r--source/blender/editors/screen/area.c106
-rw-r--r--source/blender/editors/screen/screen_context.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c103
-rw-r--r--source/blender/editors/screen/screen_geometry.c2
-rw-r--r--source/blender/editors/screen/screen_intern.h5
-rw-r--r--source/blender/editors/screen/screen_ops.c30
-rw-r--r--source/blender/editors/screen/workspace_edit.c9
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c22
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c29
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c29
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c175
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c17
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c3
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_console/console_draw.c15
-rw-r--r--source/blender/editors/space_file/file_draw.c79
-rw-r--r--source/blender/editors/space_file/file_ops.c28
-rw-r--r--source/blender/editors/space_file/filelist.c96
-rw-r--r--source/blender/editors/space_file/fsmenu.c7
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c77
-rw-r--r--source/blender/editors/space_image/image_ops.c5
-rw-r--r--source/blender/editors/space_image/image_undo.c6
-rw-r--r--source/blender/editors/space_info/info_draw.c1
-rw-r--r--source/blender/editors/space_info/info_stats.c10
-rw-r--r--source/blender/editors/space_info/textview.c38
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_edit.c10
-rw-r--r--source/blender/editors/space_node/node_select.c52
-rw-r--r--source/blender/editors/space_node/node_view.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c52
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c19
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c31
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c6
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c422
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h6
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c19
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c1153
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c109
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c26
-rw-r--r--source/blender/editors/transform/transform.c184
-rw-r--r--source/blender/editors/transform/transform.h30
-rw-r--r--source/blender/editors/transform/transform_constraints.c273
-rw-r--r--source/blender/editors/transform/transform_constraints.h3
-rw-r--r--source/blender/editors/transform/transform_convert.c6
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c10
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c3
-rw-r--r--source/blender/editors/transform/transform_generics.c64
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c28
-rw-r--r--source/blender/editors/transform/transform_mode.c12
-rw-r--r--source/blender/editors/transform/transform_mode.h1
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c3
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c3
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c6
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c43
-rw-r--r--source/blender/editors/transform/transform_orientations.c143
-rw-r--r--source/blender/editors/transform/transform_snap.c113
-rw-r--r--source/blender/editors/transform/transform_snap_object.c35
-rw-r--r--source/blender/editors/undo/memfile_undo.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c21
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c20
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h11
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c111
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c206
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c5
133 files changed, 4653 insertions, 1708 deletions
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 5f3b876efaf..d3d00fc44f2 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -432,7 +432,6 @@ int join_armature_exec(bContext *C, wmOperator *op)
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
- BKE_armature_refresh_layer_used(arm);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -689,9 +688,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 5) restore original conditions */
ED_armature_to_edit(ob_old->data);
-
ED_armature_edit_refresh_layer_used(ob_old->data);
- BKE_armature_refresh_layer_used(ob_new->data);
/* parents tips remain selected when connected children are removed. */
ED_armature_edit_deselect_all(ob_old);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index daab945c106..0cd3afc9cf9 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -906,8 +906,6 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_set_array(&ptr, "layers", layers);
if (prev_ob != ob) {
- BKE_armature_refresh_layer_used(ob->data);
-
/* Note, notifier might evolve. */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 481282d6df3..d9621dba730 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -1239,51 +1239,60 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
return OPERATOR_FINISHED;
}
-/* common code for defining RNA properties */
-/* TODO: Skip save on these? */
+/**
+ * Common code for defining RNA properties.
+ */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna,
- "percentage",
- 0.5f,
- 0.0f,
- 1.0f,
- "Percentage",
- "Weighting factor for which keyframe is favored more",
- 0.0,
- 1.0);
-
- RNA_def_int(ot->srna,
- "prev_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Previous Keyframe",
- "Frame number of keyframe immediately before the current frame",
- 0,
- 50);
- RNA_def_int(ot->srna,
- "next_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Next Keyframe",
- "Frame number of keyframe immediately after the current frame",
- 0,
- 50);
-
- RNA_def_enum(ot->srna,
- "channels",
- prop_channels_types,
- PS_TFM_ALL,
- "Channels",
- "Set of properties that are affected");
- RNA_def_enum(ot->srna,
- "axis_lock",
- prop_axis_lock_types,
- 0,
- "Axis Lock",
- "Transform axis to restrict effects to");
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.0,
+ 1.0);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "prev_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Previous Keyframe",
+ "Frame number of keyframe immediately before the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "next_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Next Keyframe",
+ "Frame number of keyframe immediately after the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------------------------------ */
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index d6256f67066..4d783396888 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4923,7 +4923,7 @@ bool ED_curve_editnurb_select_pick(
}
}
else {
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
if (bezt) {
@@ -5635,7 +5635,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- vc.bmain, vc.scene, 0, vc.region, vc.v3d);
+ vc.scene, 0, vc.region, vc.v3d);
ED_transform_snap_object_project_view3d(
snap_context,
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 91d5ea58361..bacdd5b69b5 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -138,7 +138,7 @@ Nurb *ED_curve_add_nurbs_primitive(
copy_v3_v3(zvec, rv3d->viewinv[2]);
}
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
/* these types call this function to return a Nurb */
if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) {
@@ -521,7 +521,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/curve/editcurve_query.c b/source/blender/editors/curve/editcurve_query.c
index 0b15d9e55b9..132f7e58e71 100644
--- a/source/blender/editors/curve/editcurve_query.c
+++ b/source/blender/editors/curve/editcurve_query.c
@@ -44,8 +44,13 @@
/** \name Cursor Picking API
* \{ */
-static void ED_curve_pick_vert__do_closest(
- void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void ED_curve_pick_vert__do_closest(void *userData,
+ Nurb *nu,
+ BPoint *bp,
+ BezTriple *bezt,
+ int beztindex,
+ bool handles_visible,
+ const float screen_co[2])
{
struct {
BPoint *bp;
@@ -64,6 +69,8 @@ static void ED_curve_pick_vert__do_closest(
flag = bp->f1;
}
else {
+ BLI_assert(handles_visible || beztindex == 1);
+
if (beztindex == 0) {
flag = bezt->f1;
}
@@ -92,6 +99,8 @@ static void ED_curve_pick_vert__do_closest(
data->hpoint = bezt ? beztindex : 0;
data->is_changed = true;
}
+
+ UNUSED_VARS_NDEBUG(handles_visible);
}
bool ED_curve_pick_vert(ViewContext *vc,
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 9cf61d02677..9294bc6e91b 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -590,8 +590,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
changed = ED_curve_deselect_all(cu->editnurb);
break;
case SEL_INVERT:
- changed = ED_curve_select_swap(
- cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0);
+ changed = ED_curve_select_swap(cu->editnurb,
+ v3d->overlay.handle_display == CURVE_HANDLE_NONE);
break;
}
@@ -772,7 +772,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
if (last == bp) {
direction = 1 - direction;
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
}
last = bp;
@@ -826,8 +826,10 @@ static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, 1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -861,8 +863,10 @@ static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, -1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -1392,6 +1396,7 @@ static int select_nth_exec(bContext *C, wmOperator *op)
if (ed_curve_select_nth(obedit->data, &op_params) == true) {
changed = true;
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 68a204c04a7..1f3edf31b19 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
gizmo_types/dial3d_gizmo.c
gizmo_types/move3d_gizmo.c
gizmo_types/primitive3d_gizmo.c
+ gizmo_types/snap3d_gizmo.c
)
set(LIB
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 374b7b1f6a2..db57a33f543 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -382,7 +382,7 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
switch (area->spacetype) {
case SPACE_VIEW3D: {
inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
+ CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
break;
}
default:
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
new file mode 100644
index 00000000000..1fdf1160d09
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -0,0 +1,564 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file snap3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Snap Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Snap gizmo which exposes the location, normal and index in the props.
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h" /* icons */
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+typedef struct SnapGizmo3D {
+ wmGizmo gizmo;
+ PropertyRNA *prop_prevpoint;
+ PropertyRNA *prop_location;
+ PropertyRNA *prop_normal;
+ PropertyRNA *prop_elem_index;
+ PropertyRNA *prop_snap_force;
+
+ /* We could have other snap contexts, for now only support 3D view. */
+ SnapObjectContext *snap_context_v3d;
+ int mval[2];
+ short snap_elem;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmKeyMap *keymap;
+ int snap_on;
+ bool invert_snap;
+#endif
+ int use_snap_override;
+} SnapGizmo3D;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap);
+ if (!keymap) {
+ return false;
+ }
+
+ int snap_on = gizmo_snap->snap_on;
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+
+ if (kmi->propvalue == snap_on) {
+ if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
+ (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
+ (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
+ ((kmi->type == EVT_OSKEY) && event->oskey)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name ED_gizmo_library specific API
+ * \{ */
+
+void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type)
+{
+ if (!loc_prev && !loc_curr) {
+ return;
+ }
+
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
+
+ /* The size of the circle is larger than the vertex size.
+ * This prevents a drawing overlaps the other. */
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (loc_curr) {
+ immUniformColor4ubv(color_point);
+ imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos);
+
+ /* draw normal if needed */
+ if (normal) {
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_curr);
+ immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]);
+ immEnd();
+ }
+ }
+
+ if (loc_prev) {
+ /* Draw an "X" indicating where the previous snap point is.
+ * This is useful for indicating perpendicular snap. */
+
+ /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */
+ float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
+
+ /* Multiply by 0.75f so that the final size of the "X" is close to that of
+ * the circle.
+ * (A closer value is 0.7071f, but we don't need to be exact here). */
+ float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev);
+
+ mul_v3_v3fl(vx, view_inv[0], x_size);
+ mul_v3_v3fl(vy, view_inv[1], x_size);
+
+ add_v3_v3v3(v1, vx, vy);
+ sub_v3_v3v3(v2, vx, vy);
+ negate_v3_v3(v3, v1);
+ negate_v3_v3(v4, v2);
+
+ add_v3_v3(v1, loc_prev);
+ add_v3_v3(v2, loc_prev);
+ add_v3_v3(v3, loc_prev);
+ add_v3_v3(v4, loc_prev);
+
+ immUniformColor4ubv(color_line);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v4);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ /* Dashed line. */
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ immUniform1f("dash_width", 6.0f * U.pixelsize);
+ immUniform1f("dash_factor", 1.0f / 4.0f);
+ immUniformColor4ubv(color_line);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_prev);
+ immVertex3fv(pos, loc_curr);
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene,
+ const ARegion *region,
+ const View3D *v3d,
+ wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d == NULL) {
+ gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
+ scene, 0, region, v3d);
+ }
+ return gizmo_snap->snap_context_v3d;
+}
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ return gizmo_snap->invert_snap;
+}
+void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = (int)enable;
+}
+
+void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = -1;
+}
+
+short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ float co[3], no[3];
+ short snap_elem = 0;
+ int snap_elem_index[3] = {-1, -1, -1};
+ int index = -1;
+
+ if (gizmo_snap->use_snap_override != -1) {
+ if (gizmo_snap->use_snap_override == false) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (wm && wm->winactive) {
+ gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate);
+ }
+
+ if (gizmo_snap->use_snap_override == -1) {
+ const ToolSettings *ts = scene->toolsettings;
+ if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+#else
+ UNUSED_VARS(wm);
+#endif
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements");
+ int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop);
+ if (gz_prop->prop != gizmo_snap->prop_snap_force) {
+ int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force);
+ snap_elements |= snap_elements_force;
+ }
+ snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR);
+
+ if (snap_elements) {
+ float prev_co[3] = {0.0f};
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co);
+ }
+ else {
+ snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
+
+ float dist_px = 12.0f * U.pixelsize;
+
+ ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
+ snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d,
+ depsgraph,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ .use_occlusion_test = true,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ NULL);
+ }
+
+ if (snap_elem == 0) {
+ RegionView3D *rv3d = region->regiondata;
+ ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co);
+ zero_v3(no);
+ }
+ else if (snap_elem == SCE_SNAP_MODE_VERTEX) {
+ snap_elem_index[0] = index;
+ }
+ else if (snap_elem &
+ (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ snap_elem_index[1] = index;
+ }
+ else if (snap_elem == SCE_SNAP_MODE_FACE) {
+ snap_elem_index[2] = index;
+ }
+
+ gizmo_snap->snap_elem = snap_elem;
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co);
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no);
+ RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index);
+
+ if (r_loc) {
+ copy_v3_v3(r_loc, co);
+ }
+ if (r_nor) {
+ copy_v3_v3(r_nor, no);
+ }
+
+ return snap_elem;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GIZMO_GT_snap_3d
+ * \{ */
+
+static void gizmo_snap_setup(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+
+ /* For quick access to the props. */
+ gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point");
+ gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location");
+ gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal");
+ gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index");
+ gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force");
+
+ gizmo_snap->use_snap_override = -1;
+
+ /* Prop fallback. */
+ WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1);
+
+ /* Flags. */
+ gz->flag |= WM_GIZMO_NO_TOOLTIP;
+}
+
+static void gizmo_snap_draw(const bContext *C, wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_elem == 0) {
+ return;
+ }
+
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
+
+ /* Ideally, we shouldn't assign values here.
+ * But `test_select` is not called during navigation.
+ * And `snap_elem` is not really useful in this case. */
+ if ((rv3d->rflag & RV3D_NAVIGATING) ||
+ (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) {
+ gizmo_snap->snap_elem = 0;
+ return;
+ }
+
+ float location[3], prev_point_stack[3], *prev_point = NULL;
+ uchar color_line[4], color_point[4];
+
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location);
+
+ UI_GetThemeColor3ubv(TH_TRANSFORM, color_line);
+ color_line[3] = 128;
+
+ rgba_float_to_uchar(color_point, gz->color);
+
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack);
+ prev_point = prev_point_stack;
+ }
+
+ GPU_line_smooth(false);
+
+ GPU_line_width(1.0f);
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem);
+}
+
+static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmWindowManager *wm = CTX_wm_manager(C);
+ const bool invert = invert_snap(gz, wm, wm->winactive->eventstate);
+ if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] &&
+ gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+ gizmo_snap->invert_snap = invert;
+#else
+ if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+#endif
+ copy_v2_v2_int(gizmo_snap->mval, mval);
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (gizmo_snap->keymap == NULL) {
+ gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map");
+ gizmo_snap->snap_on = -1;
+ RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on);
+ }
+#endif
+
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL);
+
+ if (snap_elem) {
+ ED_region_tag_redraw_editor_overlays(region);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int gizmo_snap_modal(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event),
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_snap_invoke(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_snap_free(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d) {
+ ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d);
+ gizmo_snap->snap_context_v3d = NULL;
+ }
+}
+
+static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_snap_3d";
+
+ /* api callbacks */
+ gzt->setup = gizmo_snap_setup;
+ gzt->draw = gizmo_snap_draw;
+ gzt->test_select = gizmo_snap_test_select;
+ gzt->modal = gizmo_snap_modal;
+ gzt->invoke = gizmo_snap_invoke;
+ gzt->free = gizmo_snap_free;
+
+ gzt->struct_size = sizeof(SnapGizmo3D);
+
+ const EnumPropertyItem *rna_enum_snap_element_items;
+ {
+ /* Get Snap Element Items enum. */
+ bool free;
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(NULL, &RNA_ToolSettings, NULL, &toolsettings_ptr);
+ PropertyRNA *prop = RNA_struct_find_property(&toolsettings_ptr, "snap_elements");
+ RNA_property_enum_items(
+ NULL, &toolsettings_ptr, prop, &rna_enum_snap_element_items, NULL, &free);
+
+ BLI_assert(free == false);
+ }
+
+ /* Setup. */
+ RNA_def_enum_flag(gzt->srna,
+ "snap_elements_force",
+ rna_enum_snap_element_items,
+ SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE,
+ "Snap Elements",
+ "");
+
+ RNA_def_float_vector(gzt->srna,
+ "prev_point",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Previous Point",
+ "Point that defines the location of the perpendicular snap",
+ FLT_MIN,
+ FLT_MAX);
+
+ /* Returns. */
+ RNA_def_float_vector(gzt->srna,
+ "location",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Location",
+ "Snap Point Location",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_float_vector(gzt->srna,
+ "normal",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Normal",
+ "Snap Point Normal",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_int_vector(gzt->srna,
+ "snap_elem_index",
+ 3,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Snap Element",
+ "Array index of face, edge and vert snapped",
+ INT_MIN,
+ INT_MAX);
+
+ /* Read/Write. */
+ WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1);
+}
+
+void ED_gizmotypes_snap_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_snap_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 4444396558b..4330a07057e 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -354,10 +354,6 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
/* set mode */
if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
mode = OB_MODE_PAINT_GPENCIL;
- BKE_brush_gpencil_paint_presets(bmain, ts, false);
-
- /* Ensure Palette by default. */
- BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
}
else {
mode = OB_MODE_OBJECT;
@@ -373,8 +369,16 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_PAINT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes and Paint settings.
+ * Need Draw and Vertex (used fro Tint). */
BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+
+ BKE_brush_gpencil_paint_presets(bmain, ts, false);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
+
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
@@ -466,7 +470,6 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
/* set mode */
if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
mode = OB_MODE_SCULPT_GPENCIL;
- BKE_brush_gpencil_sculpt_presets(bmain, ts, false);
}
else {
mode = OB_MODE_OBJECT;
@@ -485,6 +488,8 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
/* be sure we have brushes */
BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint);
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint);
+
+ BKE_brush_gpencil_sculpt_presets(bmain, ts, false);
}
/* setup other modes */
@@ -572,7 +577,6 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
/* set mode */
if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
mode = OB_MODE_WEIGHT_GPENCIL;
- BKE_brush_gpencil_weight_presets(bmain, ts, false);
}
else {
mode = OB_MODE_OBJECT;
@@ -591,6 +595,8 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
/* be sure we have brushes */
BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint);
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint);
+
+ BKE_brush_gpencil_weight_presets(bmain, ts, false);
}
/* setup other modes */
@@ -675,10 +681,6 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op)
/* set mode */
if (gpd->flag & GP_DATA_STROKE_VERTEXMODE) {
mode = OB_MODE_VERTEX_GPENCIL;
- BKE_brush_gpencil_vertex_presets(bmain, ts, false);
-
- /* Ensure Palette by default. */
- BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
}
else {
mode = OB_MODE_OBJECT;
@@ -697,6 +699,11 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op)
/* be sure we have brushes */
BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint);
+
+ BKE_brush_gpencil_vertex_presets(bmain, ts, false);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
}
/* setup other modes */
@@ -3656,7 +3663,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
int cfra_prv = INT_MIN;
/* init snap context for geometry projection */
- sctx = ED_transform_snap_object_context_create_view3d(bmain, scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index a98ccb1cba6..473913c5459 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -699,16 +699,13 @@ struct GP_EditableStrokes_Iter {
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \
if (BKE_gpencil_layer_is_editable(gpl)) { \
- bGPDframe *init_gpf_ = gpl->actframe; \
- if (is_multiedit_) { \
- init_gpf_ = gpl->frames.first; \
- } \
+ bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
- for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \
/* skip strokes that are invalid for current view */ \
if (ED_gpencil_stroke_can_use(C, gps) == false) \
continue; \
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 309329e4649..4e83c4fb11c 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -2071,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
return;
}
- /* Eraser mode: If no active strokes, just return. */
+ /* Eraser mode: If no active strokes, add one or just return. */
if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ *
+ * This is done only if additive drawing is enabled.
+ */
bool has_layer_to_erase = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
@@ -2081,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
continue;
}
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
+ */
if (gpl->actframe && gpl->actframe->strokes.first) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ }
has_layer_to_erase = true;
break;
}
}
+ /* Ensure this gets set. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ p->gpf = p->gpl->actframe;
+ }
+
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c
index 2238d768bcd..0dfc7e0728e 100644
--- a/source/blender/editors/gpencil/gpencil_uv.c
+++ b/source/blender/editors/gpencil/gpencil_uv.c
@@ -59,8 +59,8 @@ typedef struct GpUvData {
float ob_scale;
float initial_length;
+ float initial_transform[2];
float pixel_size; /* use when mouse input is interpreted as spatial distance */
- bool is_modal;
/* Arrays of original loc/rot/scale by stroke. */
float (*array_loc)[2];
@@ -140,19 +140,12 @@ static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3])
}
}
-static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal)
+static bool gpencil_uv_transform_init(bContext *C, wmOperator *op)
{
GpUvData *opdata;
- if (is_modal) {
- float zero[2] = {0.0f};
- RNA_float_set_array(op->ptr, "location", zero);
- RNA_float_set(op->ptr, "rotation", 0.0f);
- RNA_float_set(op->ptr, "scale", 1.0f);
- }
op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__);
- opdata->is_modal = is_modal;
opdata->ob = CTX_data_active_object(C);
opdata->gpd = (bGPdata *)opdata->ob->data;
gp_point_conversion_init(C, &opdata->gsc);
@@ -164,12 +157,10 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
opdata->vinit_rotation[0] = 1.0f;
opdata->vinit_rotation[1] = 0.0f;
- if (is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(
- region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
- }
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(
+ region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
/* Calc selected strokes center. */
zero_v2(opdata->mcenter);
@@ -205,7 +196,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- /* convert to 2D */
+ /* Convert to 2D. */
gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter);
return true;
@@ -218,11 +209,9 @@ static void gpencil_uv_transform_exit(bContext *C, wmOperator *op)
opdata = op->customdata;
- if (opdata->is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- }
+ ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
@@ -253,66 +242,54 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
GpUvData *opdata = op->customdata;
bGPdata *gpd = opdata->gpd;
+
bool changed = false;
/* Get actual vector. */
float vr[2];
+ float mdiff[2];
+
sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter);
normalize_v2(vr);
- float location[2];
- RNA_float_get_array(op->ptr, "location", location);
-
- float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) :
- RNA_float_get(op->ptr, "rotation");
- uv_rotation *= SMOOTH_FACTOR;
-
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "rotation", uv_rotation);
- }
+ float uv_rotation = angle_signed_v2v2(opdata->vinit_rotation, vr);
int i = 0;
- /* Apply transformations to all strokes. */
- if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) {
- float mdiff[2];
- mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
- mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
+ /* Translate. */
+ if (mode == GP_UV_TRANSLATE) {
+
+ mdiff[0] = opdata->mouse[0] - opdata->initial_transform[0];
+ /* Y axis is inverted. */
+ mdiff[1] = (opdata->mouse[1] - opdata->initial_transform[1]) * -1.0f;
/* Apply a big amount of smooth always for translate to get smooth result. */
- mul_v2_fl(mdiff, 0.006f);
+ mul_v2_fl(mdiff, 0.002f);
+ RNA_float_set_array(op->ptr, "location", mdiff);
- /* Apply angle in translation. */
- mdiff[0] *= cos(uv_rotation);
- mdiff[1] *= sin(uv_rotation);
- if (opdata->is_modal) {
- RNA_float_set_array(op->ptr, "location", mdiff);
- }
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
- changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f));
- if (changed) {
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- if (opdata->is_modal) {
- add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
- }
- else {
- copy_v2_v2(gps->uv_translation, location);
- }
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
- i++;
- }
+ sub_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
+ changed = true;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) {
- changed = (bool)(uv_rotation != 0.0f);
+ /* Rotate. */
+ if (mode == GP_UV_ROTATE) {
+ changed |= (bool)(uv_rotation != 0.0f);
+ RNA_float_set(op->ptr, "rotation", uv_rotation);
+
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation;
+ gps->uv_rotation = opdata->array_rot[i] - uv_rotation;
+
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -322,25 +299,22 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) {
- float mdiff[2];
+ /* Scale. */
+ if (mode == GP_UV_SCALE) {
mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
- float scale = (opdata->is_modal) ?
- ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
- opdata->ob_scale :
- RNA_float_get(op->ptr, "scale");
+ float scale = ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
+ opdata->ob_scale;
+
scale *= SMOOTH_FACTOR;
+ RNA_float_set(op->ptr, "scale", scale);
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "scale", scale);
- }
+ changed |= (bool)(scale != 0.0f);
- changed = (bool)(scale != 0.0f);
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale;
+ gps->uv_scale = opdata->array_scale[i] + scale;
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -350,7 +324,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((!opdata->is_modal) || (changed)) {
+ if (changed) {
/* Update cursor line. */
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
@@ -360,21 +334,6 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
return changed;
}
-static int gpencil_transform_fill_exec(bContext *C, wmOperator *op)
-{
- if (!gpencil_uv_transform_init(C, op, false)) {
- return OPERATOR_CANCELLED;
- }
-
- if (!gpencil_uv_transform_calc(C, op)) {
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_FINISHED;
-}
-
static bool gpencil_transform_fill_poll(bContext *C)
{
if (!ED_operator_view3d_active(C)) {
@@ -404,7 +363,7 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
float mlen[2];
float center_3d[3];
- if (!gpencil_uv_transform_init(C, op, true)) {
+ if (!gpencil_uv_transform_init(C, op)) {
return OPERATOR_CANCELLED;
}
@@ -414,16 +373,22 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
opdata->mouse[1] = event->mval[1];
copy_v3_v3(center_3d, opdata->ob->loc);
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
+ mlen[0] = event->mval[0] - opdata->mcenter[0];
+ mlen[1] = event->mval[1] - opdata->mcenter[1];
opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ /* Consider initial offset as zero position. */
+ copy_v2fl_v2i(opdata->initial_transform, event->mval);
+
+ /* Consider initial position as the orientation vector. */
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ if (mode == GP_UV_ROTATE) {
+ opdata->vinit_rotation[0] = mlen[0];
+ opdata->vinit_rotation[1] = mlen[1];
+ normalize_v2(opdata->vinit_rotation);
+ }
- /* Calc init rotation vector. */
- float mouse[2] = {event->mval[0], event->mval[1]};
- sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter);
- normalize_v2(opdata->vinit_rotation);
+ opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
gpencil_uv_transform_calc(C, op);
@@ -492,7 +457,6 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot)
/* api callbacks */
ot->invoke = gpencil_transform_fill_invoke;
ot->modal = gpencil_transform_fill_modal;
- ot->exec = gpencil_transform_fill_exec;
ot->cancel = gpencil_transform_fill_cancel;
ot->poll = gpencil_transform_fill_poll;
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 07eade23506..a1a5d65b61d 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -40,9 +40,15 @@ void ED_gizmotypes_facemap_3d(void);
void ED_gizmotypes_preselect_3d(void);
void ED_gizmotypes_primitive_3d(void);
void ED_gizmotypes_blank_3d(void);
+void ED_gizmotypes_snap_3d(void);
-struct Object;
+struct ARegion;
struct bContext;
+struct Depsgraph;
+struct Object;
+struct SnapObjectContext;
+struct wmWindowManager;
+struct View3D;
struct wmGizmo;
/* -------------------------------------------------------------------- */
@@ -223,8 +229,9 @@ enum {
};
/* -------------------------------------------------------------------- */
-/* Gizmo Drawing Functions */
+/* Specific gizmos utils */
+/* dial3d_gizmo.c */
struct Dial3dParams {
int draw_options;
float angle_ofs;
@@ -241,6 +248,33 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const bool select,
struct Dial3dParams *params);
+/* snap3d_gizmo.c */
+#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
+void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type);
+struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ struct wmGizmo *gz);
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz);
+void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable);
+void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz);
+
+short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ const struct wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 2dbd979564e..58364e69679 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -34,13 +34,13 @@ struct PointerRNA;
struct Brush;
struct GP_SpaceConversion;
+struct GpRandomSettings;
struct bGPDframe;
struct bGPDlayer;
struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
struct tGPspoint;
-struct GpRandomSettings;
struct ARegion;
struct Depsgraph;
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 1dc98cfee2f..3471f9dcce9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -107,7 +107,10 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
bool ED_node_select_check(ListBase *lb);
void ED_node_select_all(ListBase *lb, int action);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
-void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+void ED_node_set_active(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct bNode *node,
+ bool *r_active_texture_changed);
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 32e62a6436c..5adc99a8ae0 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -260,6 +260,7 @@ float ED_object_new_primitive_matrix(struct bContext *C,
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
+void ED_object_add_unit_props_radius_ex(struct wmOperatorType *ot, float default_value);
void ED_object_add_unit_props_radius(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
@@ -268,6 +269,7 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
unsigned short *local_view_bits,
bool *is_view_aligned);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index d3fc5174dd9..0325ad9fdba 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -29,6 +29,7 @@ extern "C" {
struct Base;
struct ListBase;
+struct SpaceOutliner;
struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 43f3a578bfe..bc6a4b23609 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -347,6 +347,7 @@ bool ED_operator_info_active(struct bContext *C);
bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
+bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
bool ED_operator_object_active_editable_font(struct bContext *C);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 27b7511c8a2..9969acd04b7 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -158,7 +158,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_CURSOR_EDIT (1 << 14)
#define P_CLNOR_INVALIDATE (1 << 15)
/* For properties performed when confirming the transformation. */
-#define P_POST_TRANSFORM (1 << 16)
+#define P_POST_TRANSFORM (1 << 19)
void Transform_Properties(struct wmOperatorType *ot, int flags);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index b998ac87819..8feb73436a6 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -77,11 +77,8 @@ struct SnapObjectParams {
};
typedef struct SnapObjectContext SnapObjectContext;
-SnapObjectContext *ED_transform_snap_object_context_create(struct Main *bmain,
- struct Scene *scene,
- int flag);
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Main *bmain,
- struct Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag);
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene,
int flag,
/* extra args for view3d */
const struct ARegion *region,
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 8c565536c71..f656aaf9c07 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -50,20 +50,17 @@ void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
bool ED_uvedit_minmax(const struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
float min[2],
float max[2]);
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_min[2],
float r_max[2]);
bool ED_uvedit_center_multi(const struct Scene *scene,
- Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_cent[2],
@@ -95,11 +92,7 @@ void ED_object_assign_active_image(struct Main *bmain,
bool ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-bool uvedit_face_visible_nolocal_ex(const struct ToolSettings *ts, struct BMFace *efa);
-bool uvedit_face_visible_test_ex(const struct ToolSettings *ts,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -110,11 +103,7 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_visible_test(const struct Scene *scene,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
bool uvedit_face_select_test(const struct Scene *scene,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -175,12 +164,10 @@ void uvedit_uv_select_disable(struct BMEditMesh *em,
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
- struct Image *ima,
const float co[2],
float *dist_sq,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 668ca3c6437..beca517f0a6 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -129,6 +129,9 @@ enum eV3DCursorOrient {
void ED_view3d_background_color_get(const struct Scene *scene,
const struct View3D *v3d,
float r_color[3]);
+bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
+ const struct Object *ob,
+ const struct View3D *v3d);
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
const bool use_depth,
@@ -246,6 +249,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
struct BPoint *bp,
struct BezTriple *bezt,
int beztindex,
+ bool handle_visible,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8b7b0430765..c95f517b155 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -239,6 +239,8 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
+#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
+
/* but->drawflag - these flags should only affect how the button is drawn. */
/* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions
* (except for the 'align' ones)!
@@ -1679,6 +1681,7 @@ void UI_panel_end(const struct ScrArea *area,
int width,
int height,
bool open);
+
void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
int UI_panel_size_y(const struct Panel *panel);
@@ -1702,6 +1705,24 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_
struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
+/* Polyinstantiated panels for representing a list of data. */
+struct Panel *UI_panel_add_instanced(struct ScrArea *area,
+ struct ARegion *region,
+ struct ListBase *panels,
+ char *panel_idname,
+ int list_index);
+void UI_panels_free_instanced(struct bContext *C, struct ARegion *region);
+
+#define LIST_PANEL_UNIQUE_STR_LEN 4
+void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
+
+void UI_panel_set_expand_from_list_data(const struct bContext *C, struct Panel *panel);
+
+typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+bool UI_panel_list_matches_data(struct ARegion *region,
+ struct ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func);
+
/* Handlers
*
* Handlers that can be registered in regions, areas and windows for
@@ -2417,6 +2438,8 @@ uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PropertyRNA **r_prop,
int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
+void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
+
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index c2c27af9770..e4fb0631f06 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -68,9 +68,9 @@ set(SRC
interface_region_tooltip.c
interface_regions.c
interface_style.c
- interface_templates.c
interface_template_search_menu.c
interface_template_search_operator.c
+ interface_templates.c
interface_undo.c
interface_utils.c
interface_widgets.c
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 09811fab52d..32cae609395 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -124,7 +124,11 @@ bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
{
- switch (RGN_ALIGN_ENUM_FROM_MASK(region->alignment)) {
+ const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ?
+ region->prev :
+ region;
+
+ switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) {
case RGN_ALIGN_TOP:
return UI_BUT_ALIGN_DOWN;
case RGN_ALIGN_BOTTOM:
@@ -502,7 +506,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
butal->but->drawflag |= align;
butal_other->but->drawflag |= align_opp;
- if (butal->dists[side]) {
+ if (!IS_EQF(butal->dists[side], 0.0f)) {
float *delta = &butal->dists[side];
if (*butal->borders[side] < *butal_other->borders[side_opp]) {
@@ -513,7 +517,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
}
co = (*butal->borders[side] += *delta);
- if (butal_other->dists[side_opp]) {
+ if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) {
BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
*butal_other->borders[side_opp] = co;
butal_other->dists[side_opp] = 0.0f;
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 7527a1e0662..ace367fd513 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -82,11 +82,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
+ const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
if ((eye->ptr.data == NULL) || (eye->prop == NULL) ||
(RNA_property_editable(&eye->ptr, eye->prop) == false) ||
(RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
- (RNA_property_type(eye->prop) != PROP_FLOAT)) {
+ (RNA_property_type(eye->prop) != PROP_FLOAT) ||
+ (ELEM(prop_subtype, PROP_COLOR, PROP_COLOR_GAMMA) == 0)) {
MEM_freeN(eye);
return false;
}
@@ -96,7 +98,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
- if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
+ if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -290,7 +292,10 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index be23eacafff..24d06361c54 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,10 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index d9c77c26941..f2217db9b7d 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -316,7 +316,10 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 907da917e75..5c85edc94a1 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -311,7 +311,10 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index 89c087855bc..276cc70f2b5 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,10 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index ebde1d54c07..eb99d044e17 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -5559,7 +5559,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->type == UI_BTYPE_MENU) {
if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
- const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
+ const int direction = (event->type == WHEELDOWNMOUSE) ? 1 : -1;
data->value = ui_but_menu_step(but, direction);
@@ -8337,6 +8337,11 @@ void UI_context_active_but_prop_handle(bContext *C)
}
}
+void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
+{
+ wm_event_handler_ui_cancel_ex(C, win, region, false);
+}
+
wmOperator *UI_context_active_operator_get(const struct bContext *C)
{
ARegion *region_ctx = CTX_wm_region(C);
@@ -8868,7 +8873,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
if (post_but) {
button_activate_init(C, region, post_but, post_type);
}
- else {
+ else if (!((event->type == EVT_BUT_CANCEL) && (event->val == 1))) {
/* XXX issue is because WM_event_add_mousemove(wm) is a bad hack and not reliable,
* if that gets coded better this bypass can go away too.
*
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 3748dbab519..6cd990ec2b0 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -105,7 +105,6 @@ extern const char ui_radial_dir_to_numpad[8];
extern const short ui_radial_dir_to_angle[8];
/* internal panel drawing defines */
-#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */
/* bit button defines */
@@ -868,6 +867,7 @@ struct GPUBatch *ui_batch_roundbox_shadow_get(void);
void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_box_opaque(rcti *rect, int roundboxalign);
void ui_draw_popover_back(struct ARegion *region,
struct uiStyle *style,
uiBlock *block,
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 04179721305..54f60a05cfd 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -108,8 +109,14 @@ typedef struct uiHandlePanelData {
int startsizex, startsizey;
} uiHandlePanelData;
+typedef struct PanelSort {
+ Panel *panel, *orig;
+} PanelSort;
+
static int get_panel_real_size_y(const Panel *panel);
static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
+static int compare_panel(const void *a1, const void *a2);
+static bool panel_type_context_poll(PanelType *panel_type, const char *context);
static void panel_title_color_get(bool show_background, uchar color[4])
{
@@ -235,9 +242,335 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
return false;
}
+/********* Functions for instanced panels. ***********/
+
+static Panel *UI_panel_add_instanced_ex(
+ ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index)
+{
+ Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
+ panel->type = panel_type;
+ BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
+
+ panel->runtime.list_index = list_index;
+
+ /* Add the panel's children too. Although they aren't instanced panels, we can still use this
+ * function to create them, as UI_panel_begin does other things we don't need to do. */
+ LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
+ PanelType *child_type = child->data;
+ UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index);
+ }
+
+ /* Make sure the panel is added to the end of the display-order as well. This is needed for
+ * loading existing files.
+ *
+ * Note: We could use special behavior to place it after the panel that starts the list of
+ * instanced panels, but that would add complexity that isn't needed for now. */
+ int max_sortorder = 0;
+ LISTBASE_FOREACH (Panel *, existing_panel, panels) {
+ if (existing_panel->sortorder > max_sortorder) {
+ max_sortorder = existing_panel->sortorder;
+ }
+ }
+ panel->sortorder = max_sortorder + 1;
+
+ BLI_addtail(panels, panel);
+
+ return panel;
+}
+
+/**
+ * Called in situations where panels need to be added dynamically rather than having only one panel
+ * corresponding to each PanelType.
+ */
+Panel *UI_panel_add_instanced(
+ ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index)
+{
+ ARegionType *region_type = region->type;
+
+ PanelType *panel_type = BLI_findstring(
+ &region_type->paneltypes, panel_idname, offsetof(PanelType, idname));
+
+ if (panel_type == NULL) {
+ printf("Panel type '%s' not found.\n", panel_idname);
+ return NULL;
+ }
+
+ return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index);
+}
+
+/**
+ * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for
+ * instanced panels, where there can be multiple with the same type and idname.
+ */
+void UI_list_panel_unique_str(Panel *panel, char *r_name)
+{
+ snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index);
+}
+
+/**
+ * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store
+ * a reference to their corresponding #uiBlock.
+ */
+static void panel_free_block(ARegion *region, Panel *panel)
+{
+ BLI_assert(panel->type);
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME);
+ char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ if (STREQ(block->name, block_name)) {
+ BLI_remlink(&region->uiblocks, block);
+ UI_block_free(NULL, block);
+ break; /* Only delete one block for this panel. */
+ }
+ }
+}
+
+/**
+ * Free a panel and it's children.
+ *
+ * \note The only panels that should need to be deleted at runtime are panels with the
+ * #PNL_INSTANCED flag set.
+ */
+static void panel_delete(ARegion *region, ListBase *panels, Panel *panel)
+{
+ /* Recursively delete children. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) {
+ panel_delete(region, &panel->children, child);
+ }
+ BLI_freelistN(&panel->children);
+
+ panel_free_block(region, panel);
+
+ BLI_remlink(panels, panel);
+ if (panel->activedata) {
+ MEM_freeN(panel->activedata);
+ }
+ MEM_freeN(panel);
+}
+
+void UI_panels_free_instanced(bContext *C, ARegion *region)
+{
+ /* Delete panels with the instanced flag. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, panel, &region->panels) {
+ if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) {
+ /* Make sure the panel's handler is removed before deleting it. */
+ if (panel->activedata != NULL) {
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ }
+ panel_delete(region, &region->panels, panel);
+ }
+ }
+}
+
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the panel type idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
+bool UI_panel_list_matches_data(ARegion *region,
+ ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func)
+{
+ int data_len = BLI_listbase_count(data);
+ int i = 0;
+ Link *data_link = data->first;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type != NULL && panel->type->flag & PNL_INSTANCED) {
+ /* The panels were reordered by drag and drop. */
+ if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) {
+ return false;
+ }
+
+ /* We reached the last data item before the last instanced panel. */
+ if (data_link == NULL) {
+ return false;
+ }
+
+ /* Check if the panel type matches the panel type from the data item. */
+ char panel_idname[MAX_NAME];
+ panel_idname_func(data_link, panel_idname);
+ if (!STREQ(panel_idname, panel->type->idname)) {
+ return false;
+ }
+
+ data_link = data_link->next;
+ i++;
+ }
+ }
+
+ /* If we didn't make it to the last list item, the panel list isn't complete. */
+ if (i != data_len) {
+ return false;
+ }
+
+ return true;
+}
+
+static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel)
+{
+ /* Without a type we cannot access the reorder callback. */
+ if (drag_panel->type == NULL) {
+ return;
+ }
+ /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */
+ if (drag_panel->type->reorder == NULL) {
+ return;
+ }
+
+ char *context = drag_panel->type->context;
+
+ /* Find how many instanced panels with this context string. */
+ int list_panels_len = 0;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ list_panels_len++;
+ }
+ }
+ }
+ }
+
+ /* Sort the matching instanced panels by their display order. */
+ PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), "instancedpanelsort");
+ PanelSort *sort_index = panel_sort;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ sort_index->panel = MEM_dupallocN(panel);
+ sort_index->orig = panel;
+ sort_index++;
+ }
+ }
+ }
+ }
+ qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel);
+
+ /* Find how many of those panels are above this panel. */
+ int move_to_index = 0;
+ for (; move_to_index < list_panels_len; move_to_index++) {
+ if (panel_sort[move_to_index].orig == drag_panel) {
+ break;
+ }
+ }
+
+ /* Free panel sort array. */
+ int i = 0;
+ for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) {
+ MEM_freeN(sort_index->panel);
+ }
+ MEM_freeN(panel_sort);
+
+ /* Don't reorder the panel didn't change order after being dropped. */
+ if (move_to_index == drag_panel->runtime.list_index) {
+ return;
+ }
+
+ /* Set the bit to tell the interface to instanced the list. */
+ drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+
+ /* Finally, move this panel's list item to the new index in its list. */
+ drag_panel->type->reorder(C, drag_panel, move_to_index);
+}
+
+/**
+ * Recursive implementation for #UI_panel_set_expand_from_list_data.
+ */
+static void panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index)
+{
+ bool open = (flag & (1 << *flag_index));
+ if (open) {
+ panel->flag &= ~PNL_CLOSEDY;
+ }
+ else {
+ panel->flag |= PNL_CLOSEDY;
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ panel_set_expand_from_list_data_recursive(child, flag, flag_index);
+ }
+}
+
+/**
+ * Set the expansion of the panel and its subpanels from the flag stored by the list data
+ * corresponding to this panel. The flag has expansion stored in each bit in depth first
+ * order.
+ */
+void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel)
+{
+ BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type->flag & PNL_INSTANCED);
+ if (panel->type->get_list_data_expand_flag == NULL) {
+ /* Instanced panel doesn't support loading expansion. */
+ return;
+ }
+
+ short expand_flag = panel->type->get_list_data_expand_flag(C, panel);
+ short flag_index = 0;
+ panel_set_expand_from_list_data_recursive(panel, expand_flag, &flag_index);
+}
+
+/**
+ * Recursive implementation for #set_panels_list_data_expand_flag.
+ */
+static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index)
+{
+ bool open = !(panel->flag & PNL_CLOSEDY);
+ if (open) {
+ *flag |= (1 << *flag_index);
+ }
+ else {
+ *flag &= ~(1 << *flag_index);
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ get_panel_expand_flag(child, flag, flag_index);
+ }
+}
+
+/**
+ * Call the callback to store the panel and subpanel expansion settings in the list item that
+ * corresponds to this panel.
+ *
+ * \note This needs to iterate through all of the regions panels because the panel with changed
+ * expansion could have been the subpanel of a instanced panel, meaning it might not know
+ * which list item it corresponds to.
+ */
+static void set_panels_list_data_expand_flag(const bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ PanelType *panel_type = panel->type;
+ if (panel_type == NULL) {
+ continue;
+ }
+
+ if (panel->type->flag & PNL_INSTANCED) {
+ short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */
+ short flag_index = 0;
+ get_panel_expand_flag(panel, &expand_flag, &flag_index);
+ if (panel->type->set_list_data_expand_flag) {
+ panel->type->set_list_data_expand_flag(C, panel, expand_flag);
+ }
+ }
+ }
+}
+
/****************************** panels ******************************/
-static void panels_collapse_all(ScrArea *area, ARegion *region, const Panel *from_panel)
+static void panels_collapse_all(const bContext *C,
+ ScrArea *area,
+ ARegion *region,
+ const Panel *from_panel)
{
const bool has_category_tabs = UI_panel_category_is_visible(region);
const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL;
@@ -259,6 +592,15 @@ static void panels_collapse_all(ScrArea *area, ARegion *region, const Panel *fro
}
}
}
+ set_panels_list_data_expand_flag(C, region);
+}
+
+static bool panel_type_context_poll(PanelType *panel_type, const char *context)
+{
+ if (panel_type->context[0] && STREQ(panel_type->context, context)) {
+ return true;
+ }
+ return false;
}
Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
@@ -568,7 +910,7 @@ static void ui_draw_aligned_panel_header(
Panel *panel = block->panel;
rcti hrect;
int pnl_icons;
- const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
+ const char *activename = panel->drawname;
const bool is_subpanel = (panel->type && panel->type->parent);
uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
uchar col_title[4];
@@ -614,7 +956,6 @@ void ui_draw_aligned_panel(uiStyle *style,
const bool show_background)
{
Panel *panel = block->panel;
- rcti headrect;
rctf itemrect;
float color[4];
const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
@@ -625,11 +966,19 @@ void ui_draw_aligned_panel(uiStyle *style,
* can't be dragged. This may be changed in future. */
show_background);
const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK;
+ const bool draw_box_style = (panel->type && panel->type->flag & (PNL_DRAW_BOX));
+
+ /* Use the theme for box widgets for box-style panels. */
+ uiWidgetColors *box_wcol = NULL;
+ if (draw_box_style) {
+ bTheme *btheme = UI_GetTheme();
+ box_wcol = &btheme->tui.wcol_box;
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
if (show_background) {
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(panel_col);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -638,25 +987,47 @@ void ui_draw_aligned_panel(uiStyle *style,
return;
}
- /* calculate header rect */
- /* + 0.001f to prevent flicker due to float inaccuracy */
- headrect = *rect;
- headrect.ymin = headrect.ymax;
- headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f);
+ /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy */
+ rcti headrect = {
+ rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)};
- rcti titlerect = headrect;
- if (is_subpanel) {
- titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
- }
+ /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */
+ if (draw_box_style && !is_subpanel) {
+ /* Expand the top a tiny bit to give header buttons equal size above and below. */
+ rcti box_rect = {rect->xmin,
+ rect->xmax,
+ (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin,
+ headrect.ymax + U.pixelsize};
+ ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Mimick the border between aligned box widgets for the bottom of the header. */
+ if (!(is_closed_x || is_closed_y)) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(true);
+
+ immUniformColor4ubv(box_wcol->outline);
+ immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin);
+ uchar emboss_col[4];
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
+ immUniformColor4ubv(emboss_col);
+ immRectf(pos,
+ rect->xmin,
+ headrect.ymin - U.pixelsize,
+ rect->xmax,
+ headrect.ymin - U.pixelsize - 1);
+
+ GPU_blend(false);
+ immUnbindProgram();
+ }
+ }
- if (show_background && !is_subpanel) {
+ /* Draw the header backdrop. */
+ if (show_background && !is_subpanel && !draw_box_style) {
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(true);
/* draw with background color */
@@ -674,12 +1045,10 @@ void ui_draw_aligned_panel(uiStyle *style,
immEnd();
GPU_blend(false);
+ immUnbindProgram();
}
- immUnbindProgram();
-
- /* draw optional pin icon */
-
+/* draw optional pin icon */
#ifdef USE_PIN_HIDDEN
if (show_pin && (block->panel->flag & PNL_PIN))
#else
@@ -702,6 +1071,10 @@ void ui_draw_aligned_panel(uiStyle *style,
}
/* horizontal title */
+ rcti titlerect = headrect;
+ if (is_subpanel) {
+ titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
+ }
if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background);
@@ -730,9 +1103,7 @@ void ui_draw_aligned_panel(uiStyle *style,
}
}
- /* if the panel is minimized vertically:
- * (------)
- */
+ /* Draw panel backdrop. */
if (is_closed_y) {
/* skip */
}
@@ -745,11 +1116,18 @@ void ui_draw_aligned_panel(uiStyle *style,
else {
/* in some occasions, draw a border */
if (panel->flag & PNL_SELECT && !is_subpanel) {
+ float radius;
if (panel->control & UI_PNL_SOLID) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = 8.0f;
+ }
+ else if (draw_box_style) {
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = box_wcol->roundness * U.widget_unit;
}
else {
UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ radius = 0.0f;
}
UI_GetThemeColorShade4fv(TH_BACK, -120, color);
@@ -758,18 +1136,40 @@ void ui_draw_aligned_panel(uiStyle *style,
0.5f + rect->ymin,
0.5f + rect->xmax,
0.5f + headrect.ymax + 1,
- 8,
+ radius,
color);
}
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
GPU_blend(true);
- if (show_background) {
- /* panel backdrop */
- immUniformThemeColor(panel_col);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier.
+ * Note: Sub-panels blend with panels, so they can't be opaque. */
+ if (show_background && !(draw_box_style && !is_subpanel)) {
+ /* Draw the bottom subpanels . */
+ if (draw_box_style) {
+ if (panel->next) {
+ immUniformThemeColor(panel_col);
+ immRectf(
+ pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
+ }
+ else {
+ /* Change the width a little bit to line up with sides. */
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ UI_GetThemeColor4fv(panel_col, color);
+ UI_draw_roundbox_aa(true,
+ rect->xmin + U.pixelsize,
+ rect->ymin + U.pixelsize,
+ rect->xmax - U.pixelsize,
+ rect->ymax,
+ box_wcol->roundness * U.widget_unit,
+ color);
+ }
+ }
+ else {
+ immUniformThemeColor(panel_col);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ }
}
if (panel->control & UI_PNL_SCALE) {
@@ -887,10 +1287,6 @@ bool UI_panel_is_dragging(const struct Panel *panel)
return data->is_drag_drop;
}
-typedef struct PanelSort {
- Panel *panel, *orig;
-} PanelSort;
-
/**
* \note about sorting;
* the sortorder has a lower value for new panels being added.
@@ -1052,13 +1448,30 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co
ps->panel->ofsx = 0;
ps->panel->ofsy = -get_panel_size_y(ps->panel);
ps->panel->ofsx += ps->panel->runtime.region_ofsx;
+ /* Extra margin if the panel is a box style panel. */
+ if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) {
+ ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
if (align == BUT_VERTICAL) {
+ bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX;
+ bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX;
psnext->panel->ofsx = ps->panel->ofsx;
psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel);
+ /* Extra margin for box style panels. */
+ if (use_box || use_box_next) {
+ psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ if (use_box && !use_box_next) {
+ psnext->panel->ofsx -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ else if (!use_box && use_box_next) {
+ psnext->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ }
}
else {
psnext->panel->ofsx = get_panel_real_ofsx(ps->panel);
@@ -1137,7 +1550,7 @@ static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y)
*r_y = sizey;
}
-static void ui_do_animate(const bContext *C, Panel *panel)
+static void ui_do_animate(bContext *C, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
ScrArea *area = CTX_wm_area(C);
@@ -1156,7 +1569,15 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
if (fac >= 1.0f) {
+ /* Store before data is freed. */
+ const bool is_drag_drop = data->is_drag_drop;
+
panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ if (is_drag_drop) {
+ /* Note: doing this in #panel_activate_state would require removing const for context in many
+ * other places. */
+ reorder_instanced_panel_list(C, region, panel);
+ }
return;
}
}
@@ -1322,8 +1743,8 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
return;
}
- dx = (event->x - data->startx) & ~(PNL_GRID - 1);
- dy = (event->y - data->starty) & ~(PNL_GRID - 1);
+ dx = (event->x - data->startx);
+ dy = (event->y - data->starty);
dx *= (float)BLI_rctf_size_x(&region->v2d.cur) / (float)BLI_rcti_size_x(&region->winrct);
dy *= (float)BLI_rctf_size_y(&region->v2d.cur) / (float)BLI_rcti_size_y(&region->winrct);
@@ -1460,6 +1881,8 @@ static void ui_panel_drag_collapse(bContext *C,
}
}
}
+ /* Update the instanced panel data expand flags with the changes made here. */
+ set_panels_list_data_expand_flag(C, region);
}
/**
@@ -1588,7 +2011,7 @@ static void ui_handle_panel_header(
if (ctrl) {
/* Only collapse all for parent panels. */
if (block->panel->type != NULL && block->panel->type->parent == NULL) {
- panels_collapse_all(area, region, block->panel);
+ panels_collapse_all(C, area, region, block->panel);
/* reset the view - we don't want to display a view without content */
UI_view2d_offset(&region->v2d, 0.0f, 1.0f);
@@ -1624,6 +2047,8 @@ static void ui_handle_panel_header(
ui_panel_drag_collapse_handler_add(C, true);
}
}
+
+ set_panels_list_data_expand_flag(C, region);
}
if (align) {
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index 34ac58c1dca..1f8af7b9e6e 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region)
return;
}
+ ScrArea *area = CTX_wm_area(C);
int size_y = region->sizey;
ED_region_panels_layout(C, region);
- if (region->panels.first && (region->sizey != size_y)) {
+ if (region->panels.first &&
+ ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) {
int winx_new = UI_DPI_FAC * (region->sizex + 0.5f);
int winy_new = UI_DPI_FAC * (region->sizey + 0.5f);
View2D *v2d = &region->v2d;
@@ -339,6 +341,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *area)
}
else {
if (region->flag & RGN_FLAG_HIDDEN) {
+ /* Also forces recalculating HUD size in hud_region_layout(). */
area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
region->flag &= ~RGN_FLAG_HIDDEN;
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 0a06f765c0e..2c6b09168f4 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -41,6 +41,7 @@
#include "BLI_math_matrix.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -177,7 +178,19 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
struct MenuSearch_Context *wm_context)
{
struct MenuSearch_Item *item = NULL;
+
+ /* Use override if the name is empty, this can happen with popovers. */
+ const char *drawstr_override = NULL;
+ const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
+ strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
+
if (but->optype != NULL) {
+ if (drawstr_is_empty) {
+ drawstr_override = WM_operatortype_name(but->optype, but->opptr);
+ }
+
item = BLI_memarena_calloc(memarena, sizeof(*item));
item->type = MENU_SEARCH_TYPE_OP;
@@ -189,6 +202,25 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
}
else if (but->rnaprop != NULL) {
const int prop_type = RNA_property_type(but->rnaprop);
+
+ if (drawstr_is_empty) {
+ if (prop_type == PROP_ENUM) {
+ const int value_enum = (int)but->hardmax;
+ EnumPropertyItem enum_item;
+ if (RNA_property_enum_item_from_value_gettexted(
+ but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ drawstr_override = enum_item.name;
+ }
+ else {
+ /* Should never happen. */
+ drawstr_override = "Unknown";
+ }
+ }
+ else {
+ drawstr_override = RNA_property_ui_name(but->rnaprop);
+ }
+ }
+
if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
/* Note that these buttons are not prevented,
* but aren't typically used in menus. */
@@ -213,7 +245,16 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
if (item != NULL) {
/* Handle shared settings. */
- item->drawstr = strdup_memarena(memarena, but->drawstr);
+ if (drawstr_override != NULL) {
+ const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
+ char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
+ item->drawstr = strdup_memarena(memarena, drawstr_alloc);
+ MEM_freeN(drawstr_alloc);
+ }
+ else {
+ item->drawstr = strdup_memarena(memarena, but->drawstr);
+ }
+
item->icon = ui_but_icon(but);
item->state = (but->flag &
(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 0e67f943ee6..9b59e4419c4 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1150,7 +1150,7 @@ static void template_ID_tabs(bContext *C,
{
const ARegion *region = CTX_wm_region(C);
const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop);
- MenuType *mt = WM_menutype_find(menu, false);
+ MenuType *mt = menu ? WM_menutype_find(menu, false) : NULL;
const int but_align = ui_but_align_opposite_to_area_align_get(region);
const int but_height = UI_UNIT_Y * 1.1;
@@ -1220,6 +1220,8 @@ static void ui_template_id(uiLayout *layout,
const char *newop,
const char *openop,
const char *unlinkop,
+ /* Only respected by tabs (use_tabs). */
+ const char *menu,
const char *text,
int flag,
int prv_rows,
@@ -1274,7 +1276,7 @@ static void ui_template_id(uiLayout *layout,
if (template_ui->idlb) {
if (use_tabs) {
layout = uiLayoutRow(layout, true);
- template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
}
else {
layout = uiLayoutRow(layout, true);
@@ -1313,6 +1315,7 @@ void uiTemplateID(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
0,
@@ -1341,6 +1344,7 @@ void uiTemplateIDBrowse(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME,
0,
@@ -1372,6 +1376,7 @@ void uiTemplateIDPreview(uiLayout *layout,
openop,
unlinkop,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
rows,
cols,
@@ -1399,6 +1404,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
NULL,
NULL,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE,
rows,
cols,
@@ -1417,7 +1423,7 @@ void uiTemplateIDTabs(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
const char *newop,
- const char *unlinkop,
+ const char *menu,
int filter)
{
ui_template_id(layout,
@@ -1426,7 +1432,8 @@ void uiTemplateIDTabs(uiLayout *layout,
propname,
newop,
NULL,
- unlinkop,
+ NULL,
+ menu,
NULL,
UI_ID_BROWSE | UI_ID_RENAME,
0,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 4706be205e1..0498b312618 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4265,7 +4265,7 @@ static void widget_box(
copy_v3_v3_uchar(old_col, wcol->inner);
/* abuse but->hsv - if it's non-zero, use this color as the box's background */
- if (but->col[3]) {
+ if (but != NULL && but->col[3]) {
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
@@ -5021,6 +5021,30 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
/**
+ * Uses the widget base drawing and colors from from the box widget, but ensures an opaque
+ * inner color.
+ */
+void ui_draw_box_opaque(rcti *rect, int roundboxalign)
+{
+ uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
+
+ /* Alpha blend with the region's background color to force an opaque background. */
+ uiWidgetColors *wcol = &wt->wcol;
+ wt->state(wt, 0, 0);
+ float background[4];
+ UI_GetThemeColor4fv(TH_BACK, background);
+ float new_inner[4];
+ rgba_uchar_to_float(new_inner, wcol->inner);
+ new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3]));
+ new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3]));
+ new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3]));
+ new_inner[3] = 1.0f;
+ rgba_float_to_uchar(wcol->inner, new_inner);
+
+ wt->custom(NULL, wcol, rect, 0, roundboxalign);
+}
+
+/**
* Similar to 'widget_menu_back', however we can't use the widget preset system
* because we need to pass in the original location so we know where to show the arrow.
*/
diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c
index 17a95ba3fff..36213f919a3 100644
--- a/source/blender/editors/interface/view2d_draw.c
+++ b/source/blender/editors/interface/view2d_draw.c
@@ -40,6 +40,7 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
@@ -196,7 +197,19 @@ static void draw_parallel_lines(const ParallelLinesSet *lines,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (U.pixelsize > 1.0f) {
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ /* -1.0f offset here is because the line is too fat due to the builtin antialiasing.
+ * TODO make a variant or a uniform to toggle it off. */
+ immUniform1f("lineWidth", U.pixelsize - 1.0f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
immUniformColor3ubv(color);
immBegin(GPU_PRIM_LINES, steps * 2);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 1484dcfa92d..3c426e5d2b1 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -59,6 +59,7 @@ static Object *make_prim_init(bContext *C,
const char *idname,
const float loc[3],
const float rot[3],
+ const float scale[3],
ushort local_view_bits,
MakePrimitiveData *r_creation_data)
{
@@ -76,6 +77,13 @@ static Object *make_prim_init(bContext *C,
ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
+ if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) {
+ float scale_half[3];
+ copy_v3_v3(scale_half, scale);
+ mul_v3_fl(scale_half, 0.5f);
+ rescale_m4(r_creation_data->mat, scale_half);
+ }
+
return obedit;
}
@@ -112,9 +120,16 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -164,15 +179,22 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -237,9 +259,16 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
cap_tri = (cap_end == 2);
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -294,7 +323,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -303,11 +332,13 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
@@ -368,7 +399,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -377,9 +408,15 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -447,9 +484,15 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -514,10 +557,16 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Y', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
dia = RNA_float_get(op->ptr, "size") / 2.0f;
mul_mat3_m4_fl(creation_data.mat, dia);
@@ -567,15 +616,21 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -629,17 +684,19 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index eed2cbcce39..739bc5bdf7c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "add_solidify")) {
ED_object_modifier_add(
op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify);
- SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findny_name(
+ SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name(
new_ob, "mask_extract_solidify");
if (sfmd) {
sfmd->offset = -0.05f;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index a26003d78ed..b5346a9061a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1647,14 +1647,13 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
void EDBM_project_snap_verts(
bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
{
- Main *bmain = CTX_data_main(C);
BMIter iter;
BMVert *eve;
ED_view3d_init_mats_rv3d(obedit, region->regiondata);
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
+ CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 74fba4d0cf9..8289f52b0c8 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -303,10 +303,15 @@ void ED_object_add_unit_props_size(wmOperatorType *ot)
ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
}
-void ED_object_add_unit_props_radius(wmOperatorType *ot)
+void ED_object_add_unit_props_radius_ex(wmOperatorType *ot, float default_value)
{
RNA_def_float_distance(
- ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+ ot->srna, "radius", default_value, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+}
+
+void ED_object_add_unit_props_radius(wmOperatorType *ot)
+{
+ ED_object_add_unit_props_radius_ex(ot, 1.0f);
}
void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
@@ -345,6 +350,18 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
DEG2RADF(-360.0f),
DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_float_vector_xyz(ot->srna,
+ "scale",
+ 3,
+ NULL,
+ -OBJECT_ADD_SIZE_MAXF,
+ OBJECT_ADD_SIZE_MAXF,
+ "Scale",
+ "Scale for the newly added object",
+ -1000.0f,
+ 1000.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void ED_object_add_mesh_props(wmOperatorType *ot)
@@ -357,6 +374,7 @@ bool ED_object_add_generic_get_opts(bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
ushort *local_view_bits,
bool *is_view_aligned)
@@ -465,6 +483,26 @@ bool ED_object_add_generic_get_opts(bContext *C,
}
}
+ /* Scale! */
+ {
+ float _scale[3];
+ if (!scale) {
+ scale = _scale;
+ }
+
+ /* For now this is optional, we can make it always use. */
+ copy_v3_fl(scale, 1.0f);
+ if ((prop = RNA_struct_find_property(op->ptr, "scale"))) {
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, scale);
+ }
+ else {
+ copy_v3_fl(scale, 1.0f);
+ RNA_property_float_set_array(op->ptr, prop, scale);
+ }
+ }
+ }
+
return true;
}
@@ -530,7 +568,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
radius = RNA_float_get(op->ptr, "radius");
@@ -604,7 +642,7 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -663,7 +701,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -741,7 +779,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits);
@@ -802,7 +840,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit == NULL || obedit->type != OB_MBALL) {
@@ -814,7 +852,10 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
- dia = RNA_float_get(op->ptr, "radius");
+ /* Halving here is done to account for constant values from #BKE_mball_element_add.
+ * While the default radius of the resulting meta element is 2,
+ * we want to pass in 1 so other values such as resolution are scaled by 1.0. */
+ dia = RNA_float_get(op->ptr, "radius") / 2;
ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
@@ -845,7 +886,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
- ED_object_add_unit_props_radius(ot);
+ ED_object_add_unit_props_radius_ex(ot, 2.0f);
ED_object_add_generic_props(ot, true);
}
@@ -864,7 +905,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit && obedit->type == OB_FONT) {
@@ -916,7 +957,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
@@ -979,7 +1020,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits);
@@ -1039,7 +1080,8 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
ushort local_view_bits;
float rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(
+ C, op, 'Z', NULL, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits);
@@ -1126,7 +1168,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
/* Note: We use 'Y' here (not 'Z'), as */
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
/* add new object if not currently editing a GP object,
@@ -1256,7 +1298,7 @@ static int object_light_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits);
@@ -1341,7 +1383,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"));
}
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (collection) {
@@ -1414,7 +1456,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
Scene *scene = CTX_data_scene(C);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits);
@@ -1471,7 +1513,7 @@ static int object_hair_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits);
@@ -1508,7 +1550,7 @@ static int object_pointcloud_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_POINTCLOUD, NULL, loc, rot, false, local_view_bits);
@@ -2857,6 +2899,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index c31de7f371c..e84dbca2469 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -96,6 +96,7 @@ typedef struct BakeAPIRender {
bool is_cage;
float cage_extrusion;
+ float max_ray_distance;
int normal_space;
eBakeNormalSwizzle normal_swizzle[3];
@@ -737,6 +738,7 @@ static int bake(Render *re,
const bool is_selected_to_active,
const bool is_cage,
const float cage_extrusion,
+ const float max_ray_distance,
const int normal_space,
const eBakeNormalSwizzle normal_swizzle[],
const char *custom_cage,
@@ -1010,6 +1012,7 @@ static int bake(Render *re,
num_pixels,
ob_cage != NULL,
cage_extrusion,
+ max_ray_distance,
ob_low_eval->obmat,
(ob_cage ? ob_cage->obmat : ob_low_eval->obmat),
me_cage)) {
@@ -1305,6 +1308,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage");
bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion");
+ bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance");
bkr->normal_space = RNA_enum_get(op->ptr, "normal_space");
bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r");
@@ -1394,6 +1398,7 @@ static int bake_exec(bContext *C, wmOperator *op)
true,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1426,6 +1431,7 @@ static int bake_exec(bContext *C, wmOperator *op)
false,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1495,6 +1501,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
true,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1527,6 +1534,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
false,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1586,6 +1594,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
}
+ prop = RNA_struct_find_property(op->ptr, "max_ray_distance");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, bake->max_ray_distance);
+ }
+
prop = RNA_struct_find_property(op->ptr, "cage_extrusion");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_float_set(op->ptr, prop, bake->cage_extrusion);
@@ -1766,12 +1779,23 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Selected to Active",
"Bake shading on the surface of selected objects to the active object");
RNA_def_float(ot->srna,
+ "max_ray_distance",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Max Ray Distance",
+ "The maximum ray distance for matching points between the active and selected "
+ "objects. If zero, there is no limit",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
"cage_extrusion",
0.0f,
0.0f,
FLT_MAX,
"Cage Extrusion",
- "Distance to use for the inward ray cast when using selected to active",
+ "Inflate the active object by the specified distance for baking. This helps "
+ "matching to points nearer to the outside of the selected object meshes",
0.0f,
1.0f);
RNA_def_string(ot->srna,
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 690c63a2cbf..53a557c5871 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1466,6 +1466,13 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
return item;
}
+static bool object_mode_set_poll(bContext *C)
+{
+ /* Needed as #ED_operator_object_active_editable doesn't call use 'active_object'. */
+ Object *ob = CTX_data_active_object(C);
+ return ED_operator_object_active_editable_ex(C, ob);
+}
+
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
@@ -1551,7 +1558,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_mode_set_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = object_mode_set_poll;
/* flags */
ot->flag = 0; /* no register/undo here, leave it to operators being called */
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 5cb4714dabf..9398a5f2ce7 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -805,7 +805,7 @@ bool ED_object_modifier_apply(Main *bmain,
/* Get evaluated modifier, so object links pointer to evaluated data,
* but still use original object it is applied to the original mesh. */
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findny_name(ob_eval, md->name) : md;
+ ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md;
/* allow apply of a not-realtime modifier, by first re-enabling realtime. */
prev_mode = md_eval->mode;
@@ -1020,7 +1020,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
ModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
- md = BKE_modifiers_findny_name(ob, modifier_name);
+ md = BKE_modifiers_findby_name(ob, modifier_name);
if (md && type != 0 && md->type != type) {
md = NULL;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index bfceaef4644..11e9c396552 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2072,7 +2072,7 @@ void ED_object_single_users(Main *bmain,
/* Duplicating obdata and other IDs may require another update of the collections and objects
* pointers, especially regarding drivers and custom props, see T66641.
- * Note that this whole scene duplication code and 'make single user' functions have te be
+ * Note that this whole scene duplication code and 'make single user' functions have to be
* rewritten at some point to make use of proper modern ID management code,
* but that is no small task.
* For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index 3c1f7da2bd6..4cdbbea492b 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -59,7 +59,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return false;
}
return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 6cafc51231c..306adb36c52 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -5127,7 +5127,7 @@ void PE_create_particle_edit(
int totpoint;
if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name(ob_eval,
+ psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval,
psmd->modifier.name);
}
@@ -5251,9 +5251,6 @@ static bool particle_edit_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) ||
BKE_modifiers_findby_type(ob, eModifierType_Softbody));
@@ -5301,7 +5298,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
* with possible changes applied when object was outside of the
* edit mode. */
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name(
+ edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(
object_eval, edit->psmd->modifier.name);
recalc_emitter_field(depsgraph, ob, edit->psys);
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index ceaac201da3..8524870c15e 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -52,6 +52,7 @@
#include "DEG_depsgraph.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "PIL_time.h"
@@ -154,7 +155,7 @@ static bool fluid_initjob(
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
@@ -170,7 +171,7 @@ static bool fluid_initjob(
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
job->depsgraph = CTX_data_depsgraph_pointer(C);
- job->ob = CTX_data_active_object(C);
+ job->ob = ob;
job->mmd = mmd;
job->type = op->type->idname;
job->name = op->type->name;
@@ -616,7 +617,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
Scene *scene = CTX_data_scene(C);
/*
@@ -679,7 +680,7 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
/*
* Get modifier data
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 17049fdb28b..1db7bf5a766 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -349,7 +349,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_SetReports(re, op->reports);
- BLI_threaded_malloc_begin();
if (is_animation) {
RE_RenderAnim(re,
mainp,
@@ -363,7 +362,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
else {
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- BLI_threaded_malloc_end();
RE_SetReports(re, NULL);
@@ -391,16 +389,14 @@ static void make_renderinfo_string(const RenderStats *rs,
char *str)
{
char info_time_str[32]; // used to be extern to header_info.c
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
+ uintptr_t mem_in_use, peak_memory;
+ float megs_used_memory, megs_peak_memory;
char *spos = str;
mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
peak_memory = MEM_get_peak_memory();
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
+ megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
/* local view */
@@ -441,7 +437,7 @@ static void make_renderinfo_string(const RenderStats *rs,
}
}
else {
- if (rs->totvert || rs->totface || rs->tothalo || rs->totstrand || rs->totlamp) {
+ if (rs->totvert || rs->totface || rs->totlamp) {
spos += sprintf(spos, "| ");
}
@@ -451,38 +447,16 @@ static void make_renderinfo_string(const RenderStats *rs,
if (rs->totface) {
spos += sprintf(spos, TIP_("Fa:%d "), rs->totface);
}
- if (rs->tothalo) {
- spos += sprintf(spos, TIP_("Ha:%d "), rs->tothalo);
- }
- if (rs->totstrand) {
- spos += sprintf(spos, TIP_("St:%d "), rs->totstrand);
- }
if (rs->totlamp) {
spos += sprintf(spos, TIP_("Li:%d "), rs->totlamp);
}
if (rs->mem_peak == 0.0f) {
- spos += sprintf(spos,
- TIP_("| Mem:%.2fM (%.2fM, Peak %.2fM) "),
- megs_used_memory,
- mmap_used_memory,
- megs_peak_memory);
+ spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory);
}
else {
spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak);
}
-
- if (rs->curfield) {
- spos += sprintf(spos, TIP_("Field %d "), rs->curfield);
- }
- if (rs->curblur) {
- spos += sprintf(spos, TIP_("Blur %d "), rs->curblur);
- }
- }
-
- /* full sample */
- if (rs->curfsa) {
- spos += sprintf(spos, TIP_("| Full Sample %d "), rs->curfsa);
}
/* extra info */
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index f2e8209b099..2861e851282 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -494,7 +494,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
scene,
oglrender->sizex,
oglrender->sizey,
- 100.0f,
+ 100,
false,
&context);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 48b54ddcea3..c04122edd36 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -2345,6 +2345,15 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
return false;
}
+/**
+ * Builds the panel layout for the input \a panel or type \a pt.
+ *
+ * \param panel The panel to draw. Can be null, in which case a panel with the type of \a pt will
+ * be created.
+ * \param unique_panel_str A unique identifier for the name of the \a uiBlock associated with the
+ * panel. Used when the panel is an instanced panel so a unique identifier is needed to find the
+ * correct old \a uiBlock, and NULL otherwise.
+ */
static void ed_panel_draw(const bContext *C,
ScrArea *area,
ARegion *region,
@@ -2353,18 +2362,27 @@ static void ed_panel_draw(const bContext *C,
Panel *panel,
int w,
int em,
- bool vertical)
+ bool vertical,
+ char *unique_panel_str)
{
const uiStyle *style = UI_style_get_dpi();
- /* draw panel */
- uiBlock *block = UI_block_begin(C, region, pt->idname, UI_EMBOSS);
+ /* Draw panel. */
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, pt->idname, BKE_ST_MAXNAME);
+ if (unique_panel_str != NULL) {
+ /* Instanced panels should have already been added at this point. */
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+ }
+ uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
bool open;
panel = UI_panel_begin(area, region, lb, block, pt, panel, &open);
/* bad fixed values */
int xco, yco, h = 0;
+ int headerend = w - UI_UNIT_X;
if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
/* for preset menu */
@@ -2380,8 +2398,6 @@ static void ed_panel_draw(const bContext *C,
pt->draw_header_preset(C, panel);
- int headerend = w - UI_UNIT_X;
-
UI_block_layout_resolve(block, &xco, &yco);
UI_block_translate(block, headerend - xco, 0);
panel->layout = NULL;
@@ -2391,9 +2407,24 @@ static void ed_panel_draw(const bContext *C,
int labelx, labely;
UI_panel_label_offset(block, &labelx, &labely);
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ /* Unusual case: Use expanding layout (buttons stretch to available width). */
+ if (pt->flag & PNL_LAYOUT_HEADER_EXPAND) {
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ labelx,
+ labely,
+ headerend - 2 * style->panelspace,
+ 1,
+ 0,
+ style);
+ panel->layout = uiLayoutRow(layout, false);
+ }
+ /* Regular case: Normal panel with fixed size buttons. */
+ else {
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ }
pt->draw_header(C, panel);
@@ -2449,7 +2480,16 @@ static void ed_panel_draw(const bContext *C,
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
- ed_panel_draw(C, area, region, &panel->children, child_pt, child_panel, w, em, vertical);
+ ed_panel_draw(C,
+ area,
+ region,
+ &panel->children,
+ child_pt,
+ child_panel,
+ w,
+ em,
+ vertical,
+ unique_panel_str);
}
}
}
@@ -2571,6 +2611,7 @@ void ED_region_panels_layout_ex(const bContext *C,
}
w -= margin_x;
+ int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f;
/* create panels */
UI_panels_begin(C, region);
@@ -2578,8 +2619,14 @@ void ED_region_panels_layout_ex(const bContext *C,
/* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
+ bool has_instanced_panel = false;
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
PanelType *pt = pt_link->link;
+
+ if (pt->flag & PNL_INSTANCED) {
+ has_instanced_panel = true;
+ continue;
+ }
Panel *panel = UI_panel_find_by_type(&region->panels, pt);
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
@@ -2593,7 +2640,46 @@ void ED_region_panels_layout_ex(const bContext *C,
update_tot_size = false;
}
- ed_panel_draw(C, area, region, &region->panels, pt, panel, w, em, vertical);
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ pt,
+ panel,
+ (pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ NULL);
+ }
+
+ /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
+ if (has_instanced_panel) {
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type == NULL) {
+ continue; /* Some panels don't have a type.. */
+ }
+ if (panel->type->flag & PNL_INSTANCED) {
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
+ /* Use a unique identifier for instanced panels, otherwise an old block for a different
+ * panel of the same type might be found. */
+ char unique_panel_str[8];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ panel->type,
+ panel,
+ (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ unique_panel_str);
+ }
+ }
}
/* align panels and return size */
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index b383930ddda..3202dc68f37 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -118,8 +118,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
- Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL;
+ Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 00afbf452dd..6f004238522 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -305,30 +305,28 @@ int area_getorientation(ScrArea *area, ScrArea *sb)
ScrVert *sbTR = sb->v3;
ScrVert *sbBR = sb->v4;
- int tolerance = U.pixelsize * 4;
-
if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */
- if ((abs(saBL->vec.y - sbBR->vec.y) <= tolerance) &&
- (abs(saTL->vec.y - sbTR->vec.y) <= tolerance)) {
+ if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) {
return 0;
}
}
else if (saTL->vec.y == sbBL->vec.y &&
saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */
- if ((abs(saTL->vec.x - sbBL->vec.x) <= tolerance) &&
- (abs(saTR->vec.x - sbBR->vec.x) <= tolerance)) {
+ if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) {
return 1;
}
}
else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */
- if ((abs(saTR->vec.y - sbTL->vec.y) <= tolerance) &&
- (abs(saBR->vec.y - sbBL->vec.y) <= tolerance)) {
+ if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) {
return 2;
}
}
else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/
- if ((abs(saBL->vec.x - sbTL->vec.x) <= tolerance) &&
- (abs(saBR->vec.x - sbTR->vec.x) <= tolerance)) {
+ if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) {
return 3;
}
}
@@ -336,6 +334,69 @@ int area_getorientation(ScrArea *area, ScrArea *sb)
return -1;
}
+/* Screen verts with horizontal position equal to from_x are moved to to_x. */
+static void screen_verts_halign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_x,
+ const short to_x)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.x == from_x) {
+ v1->vec.x = to_x;
+ }
+ }
+}
+
+/* Screen verts with vertical position equal to from_y are moved to to_y. */
+static void screen_verts_valign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_y,
+ const short to_y)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.y == from_y) {
+ v1->vec.y = to_y;
+ }
+ }
+}
+
+/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
+ */
+static void screen_areas_align(
+ bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ if (dir == 0 || dir == 2) {
+ /* horizontal join, use average for new top and bottom. */
+ int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
+ int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
+
+ /* Move edges exactly matching source top and bottom. */
+ screen_verts_valign(win, screen, sa1->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa1->v4->vec.y, bottom);
+
+ /* Move edges exactly matching target top and bottom. */
+ screen_verts_valign(win, screen, sa2->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa2->v4->vec.y, bottom);
+ }
+ else {
+ /* Vertical join, use averages for new left and right. */
+ int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2;
+ int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2;
+
+ /* Move edges exactly matching source left and right. */
+ screen_verts_halign(win, screen, sa1->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa1->v3->vec.x, right);
+
+ /* Move edges exactly matching target left and right */
+ screen_verts_halign(win, screen, sa2->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa2->v3->vec.x, right);
+ }
+}
+
/* Helper function to join 2 areas, it has a return value, 0=failed 1=success
* used by the split, join operators
*/
@@ -348,21 +409,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
}
/* Align areas if they are not. Do sanity checking before getting here. */
-
- if (dir == 0 || dir == 2) {
- /* horizontal join, so vertically align source vert to target */
- sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */
- sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */
- sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */
- sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */
- }
- else {
- /* vertical join, so horizontally align source verts to target */
- sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */
- sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */
- sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */
- sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */
- }
+ screen_areas_align(C, screen, sa1, sa2, dir);
if (dir == 0) { /* sa1 to right of sa2 = W */
sa1->v1 = sa2->v1; /* BL */
@@ -690,8 +737,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
ARegion *region_prev = screen->active_region;
ED_screen_areas_iter (win, screen, area_iter) {
- if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) {
- if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) {
+ if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
+ xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) {
+ if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
+ xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) {
if (ED_area_azones_update(area_iter, xy) == NULL) {
area = area_iter;
break;
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 4069795657e..47580c2f4b3 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -92,7 +92,7 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const int mx,
const int my)
{
- int safety = U.widget_unit / 10;
+ int safety = BORDERPADDING;
CLAMP_MIN(safety, 2);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 3dfc147bc73..2d42313d528 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -35,6 +35,11 @@ struct bContextDataResult;
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
+#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */
+
+/* Expanded interaction influence of area borders. */
+#define BORDERPADDING (U.dpi_fac + U.pixelsize)
+
/* area.c */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 5b808206935..f2bfcb7a395 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -339,7 +339,7 @@ bool ED_operator_console_active(bContext *C)
return ed_spacetype_test(C, SPACE_CONSOLE);
}
-static bool ed_object_hidden(Object *ob)
+static bool ed_object_hidden(const Object *ob)
{
/* if hidden but in edit mode, we still display, can happen with animation */
return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT));
@@ -351,10 +351,15 @@ bool ED_operator_object_active(bContext *C)
return ((ob != NULL) && !ed_object_hidden(ob));
}
+bool ED_operator_object_active_editable_ex(bContext *UNUSED(C), const Object *ob)
+{
+ return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+}
+
bool ED_operator_object_active_editable(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+ return ED_operator_object_active_editable_ex(C, ob);
}
bool ED_operator_object_active_editable_mesh(bContext *C)
@@ -4861,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
/** \name Show User Preferences Operator
* \{ */
-static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int userpref_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
int sizey = 520 * UI_DPI_FAC;
@@ -4899,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
- ot->invoke = userpref_show_invoke;
+ ot->exec = userpref_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4909,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
/** \name Show Drivers Editor Operator
* \{ */
-static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int drivers_editor_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
PointerRNA ptr = {NULL};
PropertyRNA *prop = NULL;
int index = -1;
@@ -4974,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_drivers_editor_show";
/* api callbacks */
- ot->invoke = drivers_editor_show_invoke;
+ ot->exec = drivers_editor_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4984,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
/** \name Show Info Log Operator
* \{ */
-static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int info_log_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = 900 * UI_DPI_FAC;
int sizey = 580 * UI_DPI_FAC;
int shift_y = 480;
@@ -5015,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_info_log_show";
/* api callbacks */
- ot->invoke = info_log_show_invoke;
+ ot->exec = info_log_show_exec;
ot->poll = ED_operator_screenactive;
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 8feef0c675a..3edc51b038b 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -109,9 +109,9 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
layout_new = win->workspace_hook->temp_layout_store;
}
else {
- layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
+ layout_new = BKE_workspace_active_layout_for_workspace_get(win->workspace_hook, workspace_new);
if (!layout_new) {
- layout_new = BKE_workspace_layouts_get(workspace_new)->first;
+ layout_new = workspace_new->layouts.first;
}
}
screen_new = BKE_workspace_layout_screen_get(layout_new);
@@ -163,7 +163,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return false;
}
- BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace_new, layout_new);
BKE_workspace_active_set(win->workspace_hook, workspace_new);
/* update screen *after* changing workspace - which also causes the
@@ -188,7 +188,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
- ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
workspace_new->flags = workspace_old->flags;
@@ -198,7 +197,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
/* TODO(campbell): tools */
- LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, layouts_old) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) {
WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(
bmain, workspace_new, layout_old, win);
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index cf9637788a9..7ce92bc3e4d 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
WorkSpaceLayout *layout_new;
- BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1);
+ BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
/* don't allow deleting temp fullscreens for now */
if (BKE_screen_is_fullscreen_area(screen_old)) {
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index e227db1c644..fd5018f76ff 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -1130,9 +1130,6 @@ static bool texture_paint_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return 1;
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index d607b6a9d6f..0f54d5e0821 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -731,7 +731,14 @@ static bool brush_generic_tool_set(bContext *C,
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
/* Tool System
- * This is needed for when there is a non-sculpt tool active (transform for e.g.) */
+ * This is needed for when there is a non-sculpt tool active (transform for e.g.).
+ * In case we are toggling (and the brush changed to the toggle_brush), we need to get the
+ * tool_name again. */
+ int tool_result = brush_tool(brush, paint->runtime.tool_offset);
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ RNA_enum_name_from_value(items, tool_result, &tool_name);
+
char tool_id[MAX_NAME];
SNPRINTF(tool_id, "builtin_brush.%s", tool_name);
WM_toolsystem_ref_set_by_id(C, tool_id);
@@ -1140,24 +1147,24 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op)
aspy *= tex->yrepeat;
}
- orig_area = aspx * aspy;
+ orig_area = fabsf(aspx * aspy);
if (do_mask) {
- stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1];
+ stencil_area = fabsf(br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]);
}
else {
- stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
+ stencil_area = fabsf(br->stencil_dimension[0] * br->stencil_dimension[1]);
}
factor = sqrtf(stencil_area / orig_area);
if (do_mask) {
- br->mask_stencil_dimension[0] = factor * aspx;
- br->mask_stencil_dimension[1] = factor * aspy;
+ br->mask_stencil_dimension[0] = fabsf(factor * aspx);
+ br->mask_stencil_dimension[1] = fabsf(factor * aspy);
}
else {
- br->stencil_dimension[0] = factor * aspx;
- br->stencil_dimension[1] = factor * aspy;
+ br->stencil_dimension[0] = fabsf(factor * aspx);
+ br->stencil_dimension[1] = fabsf(factor * aspy);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 458c24e5194..723ac58bc6e 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
SCULPT_TOOL_THUMB)) {
return false;
}
- else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ else if (SCULPT_is_cloth_deform_brush(brush)) {
return false;
}
else {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index a18a0145faa..6172b77de07 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2694,19 +2694,19 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
/* Implementation notes:
*
* Operator->invoke()
- * - validate context (add mcol)
- * - create customdata storage
- * - call paint once (mouse click)
- * - add modal handler
+ * - Validate context (add #Mesh.mloopcol).
+ * - Create custom-data storage.
+ * - Call paint once (mouse click).
+ * - Add modal handler.
*
* Operator->modal()
- * - for every mousemove, apply vertex paint
- * - exit on mouse release, free customdata
+ * - For every mouse-move, apply vertex paint.
+ * - Exit on mouse release, free custom-data.
* (return OPERATOR_FINISHED also removes handler and operator)
*
* For future:
- * - implement a stroke event (or mousemove with past positions)
- * - revise whether op->customdata should be added in object, in set_vpaint
+ * - implement a stroke event (or mouse-move with past positions).
+ * - revise whether op->customdata should be added in object, in set_vpaint.
*/
struct VPaintData {
@@ -2718,8 +2718,10 @@ struct VPaintData {
struct VertProjHandle *vp_handle;
struct CoNo *vertexcosnos;
- /* modify 'me->mcol' directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack */
+ /**
+ * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this
+ * array, otherwise we need to refresh the modifier stack.
+ */
bool use_fast_update;
/* loops tagged as having been painted, to apply shared vertex color
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 045fd54b46a..4ad6bcc5d0f 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -156,9 +156,16 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- normal_short_to_float_v3(no, ss->mvert[index].no);
- return;
+ case PBVH_FACES: {
+ if (ss->shapekey_active || ss->deform_modifiers_active) {
+ const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
+ normal_short_to_float_v3(no, mverts[index].no);
+ }
+ else {
+ normal_short_to_float_v3(no, ss->mvert[index].no);
+ }
+ break;
+ }
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
@@ -851,7 +858,7 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
SCULPT_vertex_random_access_init(ss);
flood->queue = BLI_gsqueue_new(sizeof(int));
- flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+ flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
}
void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
@@ -919,8 +926,8 @@ void SCULPT_floodfill_execute(
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
const int to_v = ni.index;
- if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) {
- flood->visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(flood->visited_vertices, to_v) && SCULPT_vertex_visible_get(ss, to_v)) {
+ BLI_BITMAP_ENABLE(flood->visited_vertices, to_v);
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
@@ -2084,9 +2091,13 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_CLOTH:
- /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
- * the same vertices. */
- if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ /* Grab deform uses the same falloff as a regular grab brush. */
+ return root_alpha * feather;
+ }
+ else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
+ * the same vertices. */
return 0.1f * alpha * flip * pressure * overlap * feather;
}
else {
@@ -6208,6 +6219,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
}
}
+/* In these brushes the grab delta is calculated always from the initial stroke location, which is
+ * generally used to create grab deformations. */
+static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
+{
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_POSE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM) ||
+ SCULPT_is_cloth_deform_brush(brush);
+}
+
+/* In these brushes the grab delta is calculated from the previous stroke location, which is used
+ * to calculate to orientate the brush tip and deformation towards the stroke direction. */
+static bool sculpt_needs_delta_for_tip_orientation(Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ return !SCULPT_is_cloth_deform_brush(brush);
+ }
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_MULTIPLANE_SCRAPE,
+ SCULPT_TOOL_CLAY_THUMB,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_SNAKE_HOOK);
+}
+
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -6251,38 +6290,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* Compute delta to move verts by. */
if (!cache->first_time) {
- switch (tool) {
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_POSE:
- case SCULPT_TOOL_THUMB:
- case SCULPT_TOOL_ELASTIC_DEFORM:
- sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, delta);
- add_v3_v3(cache->grab_delta, delta);
- break;
- case SCULPT_TOOL_CLAY_STRIPS:
- case SCULPT_TOOL_PINCH:
- case SCULPT_TOOL_CLOTH:
- case SCULPT_TOOL_MULTIPLANE_SCRAPE:
- case SCULPT_TOOL_CLAY_THUMB:
- case SCULPT_TOOL_NUDGE:
- case SCULPT_TOOL_SNAKE_HOOK:
- if (brush->flag & BRUSH_ANCHORED) {
- float orig[3];
- mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
- sub_v3_v3v3(cache->grab_delta, grab_location, orig);
- }
- else {
- sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- }
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, cache->grab_delta);
- break;
- default:
- /* Use for 'Brush.topology_rake_factor'. */
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else if (sculpt_needs_delta_for_tip_orientation(brush)) {
+ if (brush->flag & BRUSH_ANCHORED) {
+ float orig[3];
+ mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
+ sub_v3_v3v3(cache->grab_delta, grab_location, orig);
+ }
+ else {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- break;
+ }
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ /* Use for 'Brush.topology_rake_factor'. */
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
}
}
else {
@@ -6303,18 +6331,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->anchored_location, cache->true_location);
}
}
- else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_POSE)) {
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
/* Location stays the same for finding vertices in brush radius. */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -6385,9 +6409,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
if (cache->first_time ||
!((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE) ||
- (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) {
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) {
RNA_float_get_array(ptr, "location", cache->true_location);
}
@@ -7389,7 +7411,7 @@ static bool sculpt_no_multires_poll(bContext *C)
return false;
}
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -7440,7 +7462,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
MirrorModifierData mmd = {{0}};
int axis = 0;
mmd.flag = 0;
- mmd.tolerance = 0.005f;
+ mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance");
switch (sd->symmetrize_direction) {
case BMO_SYMMETRIZE_NEGATIVE_X:
axis = 0;
@@ -7497,6 +7519,16 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/* API callbacks. */
ot->exec = sculpt_symmetrize_exec;
ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Limit",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -7803,8 +7835,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
float brush_co[3];
copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
- char *visited_vertices = MEM_callocN(SCULPT_vertex_count_get(ss) * sizeof(char),
- "visited vertices");
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
/* Assuming an average of 6 edges per vertex in a triangulated mesh. */
const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
@@ -7828,8 +7859,8 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
totpoints++;
ss->preview_vert_index_list[totpoints] = to_v;
totpoints++;
- if (visited_vertices[to_v] == 0) {
- visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
const float *co = SCULPT_vertex_co_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
BLI_gsqueue_push(not_visited_vertices, &to_v);
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 62a7f1925ab..6dac2b51645 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -212,8 +212,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float *grab_delta = data->grab_delta;
float(*imat)[4] = data->mat;
- const bool use_falloff_plane = brush->cloth_force_falloff_type ==
- BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
+ const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) &&
+ brush->cloth_force_falloff_type ==
+ BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
PBVHVertexIter vd;
const float bstrength = ss->cache->bstrength;
@@ -246,14 +247,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor);
}
+ /* Original data for deform brushes. */
+ SculptOrigVertData orig_data;
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
float force[3];
const float sim_factor = cloth_brush_simulation_falloff_get(
brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]);
+ float current_vertex_location[3];
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ copy_v3_v3(current_vertex_location, orig_data.co);
+ }
+ else {
+ copy_v3_v3(current_vertex_location, vd.co);
+ }
+
/* When using the plane falloff mode the falloff is not constrained by the brush radius. */
- if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) {
+ if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) {
float dist = sqrtf(test.dist);
@@ -264,7 +280,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float fade = sim_factor * bstrength *
SCULPT_brush_strength_factor(ss,
brush,
- vd.co,
+ current_vertex_location,
dist,
vd.no,
vd.fno,
@@ -293,7 +309,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, offset, -fade);
break;
case BRUSH_CLOTH_DEFORM_GRAB:
- mul_v3_v3fl(force, grab_delta, fade);
+ /* Grab writes the positions in the simulation directly without applying forces. */
+ madd_v3_v3v3fl(
+ cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade);
+ zero_v3(force);
break;
case BRUSH_CLOTH_DEFORM_PINCH_POINT:
if (use_falloff_plane) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index f96f08e3244..cbdbab14690 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -297,6 +297,25 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
if (mode == SCULPT_FACE_SET_VISIBLE) {
+
+ /* If all vertices in the sculpt are visible, create the new face set and update the default
+ * color. This way the new face set will be white, which is a quick way of disabling all face
+ * sets and the performance hit of rendering the overlay. */
+ bool all_visible = true;
+ for (int i = 0; i < tot_vert; i++) {
+ if (!SCULPT_vertex_visible_get(ss, i)) {
+ all_visible = false;
+ break;
+ }
+ }
+
+ if (all_visible) {
+ Mesh *mesh = ob->data;
+ mesh->face_sets_color_default = next_face_set;
+ BKE_pbvh_face_sets_color_set(
+ ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
+ }
+
for (int i = 0; i < tot_vert; i++) {
if (SCULPT_vertex_visible_get(ss, i)) {
SCULPT_vertex_face_set_set(ss, i, next_face_set);
@@ -504,7 +523,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
.calc_face_normal = true,
}));
- bool *visited_faces = MEM_callocN(sizeof(bool) * mesh->totpoly, "visited faces");
+ BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
const int totfaces = mesh->totpoly;
int *face_sets = ss->face_sets;
@@ -515,12 +534,12 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
int next_face_set = 1;
for (int i = 0; i < totfaces; i++) {
- if (!visited_faces[i]) {
+ if (!BLI_BITMAP_TEST(visited_faces, i)) {
GSQueue *queue;
queue = BLI_gsqueue_new(sizeof(int));
face_sets[i] = next_face_set;
- visited_faces[i] = true;
+ BLI_BITMAP_ENABLE(visited_faces, i);
BLI_gsqueue_push(queue, &i);
while (!BLI_gsqueue_is_empty(queue)) {
@@ -537,10 +556,10 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
if (f_neighbor != f) {
int neighbor_face_index = BM_elem_index_get(f_neighbor);
- if (!visited_faces[neighbor_face_index]) {
+ if (!BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) {
if (test(bm, f, ed, f_neighbor, threshold)) {
face_sets[neighbor_face_index] = next_face_set;
- visited_faces[neighbor_face_index] = true;
+ BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index);
BLI_gsqueue_push(queue, &neighbor_face_index);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 9b13f6e6c24..6c217f66940 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -120,7 +120,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
- neighbor_iterator.index = ni.neighbors[ni.i];
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
@@ -128,8 +128,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
- neighbor_iterator.index = ni.neighbors[ni.i]; \
- neighbor_iterator.is_duplicate = (ni.i >= \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
@@ -233,7 +233,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[3],
/* Flood Fill. */
typedef struct {
GSQueue *queue;
- char *visited_vertices;
+ BLI_bitmap *visited_vertices;
} SculptFloodFill;
void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
@@ -333,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
struct SculptSession *ss,
const float outline_col[3],
float outline_alpha);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
+ brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB;
+}
+
/* Pose Brush. */
void SCULPT_do_pose_brush(struct Sculpt *sd,
struct Object *ob,
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index c7511dfc80f..35f4870fa12 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain,
}
}
+static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3])
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Move the origin and head of each segment by delta. */
+ add_v3_v3v3(segments[i].head, segments[i].initial_head, delta);
+ add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta);
+
+ /* Reset the segment rotation. */
+ unit_qt(segments[i].rot);
+ }
+}
+
+static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale)
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Assign the scale to each segment. */
+ segments[i].scale = scale;
+ }
+}
+
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -363,10 +389,14 @@ typedef struct PoseFloodFillData {
GSet *visited_face_sets;
/* In face sets origin mode, each vertex can only be assigned to one face set. */
- bool *is_weighted;
+ BLI_bitmap *is_weighted;
bool is_first_iteration;
+ /* In topology mode this stores the furthest point from the stroke origin for cases when a pose
+ * origin based on the brush radius can't be set. */
+ float fallback_floodfill_origin[3];
+
/* Fallback origin. If we can't find any face set to continue, use the position of all vertices
* that have the current face set. */
float fallback_origin[3];
@@ -377,12 +407,17 @@ static bool pose_topology_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
+ const float *co = SCULPT_vertex_co_get(ss, to_v);
if (data->pose_factor) {
data->pose_factor[to_v] = 1.0f;
}
- const float *co = SCULPT_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) <
+ len_squared_v3v3(data->pose_initial_co, co)) {
+ copy_v3_v3(data->fallback_floodfill_origin, co);
+ }
+
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
return true;
@@ -415,7 +450,7 @@ static bool pose_face_sets_floodfill_cb(
if (data->current_face_set == SCULPT_FACE_SET_NONE) {
data->pose_factor[index] = 1.0f;
- data->is_weighted[index] = true;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
@@ -446,9 +481,9 @@ static bool pose_face_sets_floodfill_cb(
if (is_vertex_valid) {
- if (!data->is_weighted[index]) {
+ if (!BLI_BITMAP_TEST(data->is_weighted, index)) {
data->pose_factor[index] = 1.0f;
- data->is_weighted[index] = true;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
visit_next = true;
}
@@ -521,12 +556,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd,
};
zero_v3(fdata.pose_origin);
copy_v3_v3(fdata.pose_initial_co, initial_location);
+ copy_v3_v3(fdata.fallback_floodfill_origin, initial_location);
SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
if (fdata.tot_co > 0) {
mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
}
+ else {
+ copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin);
+ }
/* Offset the pose origin. */
float pose_d[3];
@@ -600,9 +639,21 @@ static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain,
copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
copy_v3_v3(ik_chain->segments[i].initial_head, head);
ik_chain->segments[i].len = len_v3v3(head, origin);
+ ik_chain->segments[i].scale = 1.0f;
}
}
+static int pose_brush_num_effective_segments(const Brush *brush)
+{
+ /* Scaling multiple segments at the same time is not supported as the IK solver can't handle
+ * changes in the segment's length. It will also required a better weight distribution to avoid
+ * artifacts in the areas affected by multiple segments. */
+ if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) {
+ return 1;
+ }
+ return brush->pose_ik_segments;
+}
+
static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
Object *ob,
SculptSession *ss,
@@ -629,7 +680,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
pose_factor_grow[nearest_vertex_index] = 1.0f;
- SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert);
+ const int tot_segments = pose_brush_num_effective_segments(br);
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
/* Calculate the first segment in the chain using the brush radius and the pose origin offset. */
copy_v3_v3(next_chain_segment_target, initial_location);
@@ -688,11 +740,13 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
int totvert = SCULPT_vertex_count_get(ss);
- SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert);
+ const int tot_segments = pose_brush_num_effective_segments(br);
+
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments);
- bool *is_weighted = MEM_callocN(sizeof(bool) * totvert, "weighted");
+ BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted");
int current_face_set = SCULPT_FACE_SET_NONE;
int prev_face_set = SCULPT_FACE_SET_NONE;
@@ -802,13 +856,86 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br
MEM_SAFE_FREE(nodes);
}
+static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_translate_chain(ik_chain, ss->cache->grab_delta);
+}
+
+static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+
+ /* Solve the IK for the first segment to include rotation as part of scale. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+
+ /* Calculate a scale factor based on the grab delta. */
+ float plane[4];
+ float segment_dir[3];
+ sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig);
+ normalize_v3(segment_dir);
+ plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir);
+ const float segment_len = ik_chain->segments[0].len;
+ const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane));
+
+ /* Write the scale into the segments. */
+ pose_solve_scale_chain(ik_chain, scale);
+}
+
+static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
+ float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_roll_chain(ik_chain, brush, roll);
+}
+
+static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the IK target. */
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+
+ /* Solve the IK positions. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+}
+
+static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_twist_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_rotate_deform(ss, brush);
+ }
+}
+
+static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_translate_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_scale_deform(ss, brush);
+ }
+}
+
/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
float grab_delta[3];
- float ik_target[3];
const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
/* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be
@@ -818,26 +945,15 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ copy_v3_v3(grab_delta, ss->cache->grab_delta);
- /* Solve the positions and rotations of the IK chain. */
- if (ss->cache->invert) {
- /* Roll Mode. */
- /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
- float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength *
- 0.02f;
- BKE_curvemapping_initialize(brush->curve);
- pose_solve_roll_chain(ik_chain, brush, roll);
- }
- else {
- /* IK follow target mode. */
- /* Calculate the IK target. */
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta);
- copy_v3_v3(ik_target, ss->cache->true_location);
- add_v3_v3(ik_target, ss->cache->grab_delta);
-
- /* Solve the IK positions. */
- pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+ switch (brush->pose_deform_type) {
+ case BRUSH_POSE_DEFORM_ROTATE_TWIST:
+ sculpt_pose_do_rotate_twist_deform(ss, brush);
+ break;
+ case BRUSH_POSE_DEFORM_SCALE_TRASLATE:
+ sculpt_pose_do_scale_translate_deform(ss, brush);
+ break;
}
/* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
@@ -845,7 +961,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* This can be optimized by skipping the calculation of matrices where the symmetry is not
* enabled. */
for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) {
- for (int i = 0; i < brush->pose_ik_segments; i++) {
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
float symm_rot[4];
float symm_orig[3];
float symm_initial_orig[3];
@@ -865,6 +981,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* Create the transform matrix and store it in the segment. */
unit_m4(ik_chain->segments[i].pivot_mat[symm_it]);
quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot);
+ mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale);
translate_m4(ik_chain->segments[i].trans_mat[symm_it],
symm_orig[0] - symm_initial_orig[0],
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 912a6e1aaf6..d21552efafe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -847,6 +847,7 @@ static void sculpt_undo_free_list(ListBase *lb)
sculpt_undo_geometry_free_data(&unode->geometry_original);
sculpt_undo_geometry_free_data(&unode->geometry_modified);
+ sculpt_undo_geometry_free_data(&unode->geometry_bmesh_enter);
if (unode->face_sets) {
MEM_freeN(unode->face_sets);
@@ -913,7 +914,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL);
- unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
+ unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
for (i = 0; i < totgrid; i++) {
if (grid_hidden[grid_indices[i]]) {
@@ -974,13 +975,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
maxgrid = 0;
}
- /* We will use this while sculpting, is mapalloc slow to access then? */
-
/* General TODO, fix count_alloc. */
switch (type) {
case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+ unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
break;
@@ -994,7 +993,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
case SCULPT_UNDO_MASK:
- unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
+ unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask");
usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
@@ -1013,12 +1012,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->maxgrid = maxgrid;
unode->totgrid = totgrid;
unode->gridsize = gridsize;
- unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
+ unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
}
else {
/* Regular mesh. */
unode->maxvert = ss->totvert;
- unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
+ unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index");
}
if (ss->deform_modifiers_active) {
@@ -1571,7 +1570,7 @@ static void sculpt_undo_push_all_grids(Object *object)
/* It is possible that undo push is done from an object state where there is no PBVH. This
* happens, for example, when an operation which tagged for geometry update was performed prior
- * to the current operation without making any stroke inbetween.
+ * to the current operation without making any stroke in between.
*
* Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure
* PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index a1094dde749..d6b259c9ac0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -548,8 +548,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
UvElement *element;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
- Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
+ uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 7c2e055b1fb..9b752fbebe9 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -143,6 +143,7 @@ void ED_spacetypes_init(void)
ED_gizmotypes_blank_3d();
ED_gizmotypes_cage_2d();
ED_gizmotypes_cage_3d();
+ ED_gizmotypes_snap_3d();
/* register types for operators and gizmos */
spacetypes = BKE_spacetypes_list();
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 6b7f86a9143..5bf431be9f8 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -373,7 +373,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg)
/* set user as active */
if (user->node) {
- ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
+ ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL);
ct->texture = NULL;
}
else {
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 6c56e8dfb79..805e9608fec 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -91,7 +91,6 @@ void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy)
static int console_textview_begin(TextViewContext *tvc)
{
SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
- tvc->lheight = sc->lheight * UI_DPI_FAC;
tvc->sel_start = sc->sel_start;
tvc->sel_end = sc->sel_end;
@@ -143,10 +142,7 @@ static void console_cursor_wrap_offset(
return;
}
-static void console_textview_draw_cursor(TextViewContext *tvc,
- int cwidth,
- int columns,
- int descender)
+static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns)
{
int pen[2];
{
@@ -157,10 +153,10 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
console_cursor_wrap_offset(sc->prompt, columns, &offl, &offc, NULL);
console_cursor_wrap_offset(cl->line, columns, &offl, &offc, cl->line + cl->cursor);
pen[0] = cwidth * offc;
- pen[1] = -2 - (tvc->lheight + descender) * offl;
+ pen[1] = -tvc->lheight * offl;
console_cursor_wrap_offset(cl->line + cl->cursor, columns, &offl, &offc, NULL);
- pen[1] += (tvc->lheight + descender) * offl;
+ pen[1] += tvc->lheight * offl;
pen[0] += tvc->draw_rect.xmin;
pen[1] += tvc->draw_rect.ymin;
@@ -172,8 +168,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(TH_CONSOLE_CURSOR);
- immRectf(
- pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight + descender);
+ immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight);
immUnbindProgram();
}
@@ -229,7 +224,7 @@ static int console_textview_main__internal(SpaceConsole *sc,
/* view */
tvc.sel_start = sc->sel_start;
tvc.sel_end = sc->sel_end;
- tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC;
+ tvc.lheight = sc->lheight * UI_DPI_FAC;
tvc.scroll_ymin = v2d->cur.ymin;
tvc.scroll_ymax = v2d->cur.ymax;
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 226e7ae6b22..8d14664c0fa 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block,
const bool is_icon,
const int typeflags,
const bool drag,
- const bool dimmed)
+ const bool dimmed,
+ const bool is_link)
{
uiBut *but;
float fx, fy;
@@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon && !(typeflags & FILE_TYPE_FTFONT)) {
- /* size of center icon is scaled to fit container and UI scale */
+ if (icon && is_icon) {
+ /* Small icon in the middle of large image, scaled to fit container and UI scale */
float icon_x, icon_y;
-
- if (is_icon) {
- const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
- float icon_opacity = 0.3f;
- uchar icon_color[4] = {0, 0, 0, 255};
- float bgcolor[4];
- UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
- if (rgb_to_grayscale(bgcolor) < 0.5f) {
- icon_color[0] = 255;
- icon_color[1] = 255;
- icon_color[2] = 255;
- }
- icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
- icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
- UI_icon_draw_ex(
- icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
}
- else {
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+
+ if (is_link) {
+ /* Arrow icon to indicate it is a shortcut, link, or alias. */
+ float icon_x, icon_y;
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ const int arrow = ICON_LOOP_FORWARDS;
+ if (!is_icon) {
+ /* Arrow at very bottom-left if preview style. */
const uchar dark[4] = {0, 0, 0, 255};
const uchar light[4] = {255, 255, 255, 255};
-
- /* Smaller, fainter icon for preview image thumbnail. */
- icon_x = xco + (2.0f * UI_DPI_FAC);
- icon_y = yco + (2.0f * UI_DPI_FAC);
-
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
+ else {
+ /* Link to folder or non-previewed file. */
+ uchar icon_color[4];
+ UI_GetThemeColor4ubv(TH_BACK, icon_color);
+ icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx;
+ icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy;
+ UI_icon_draw_ex(
+ icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false);
+ }
+ }
+ else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) {
+ /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */
+ float icon_x, icon_y;
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
/* Contrasting outline around some preview types. */
@@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region)
/* don't drag parent or refresh items */
do_drag = !(FILENAME_IS_CURRPAR(file->relpath));
const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN);
+ const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK);
if (FILE_IMGDISPLAY == params->display) {
const int icon = filelist_geticon(files, i, false);
@@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region)
is_icon,
file->typeflag,
do_drag,
- is_hidden);
+ is_hidden,
+ is_link);
}
else {
file_draw_icon(block,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index a5263378850..41d32fda088 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
FileDirEntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop, &itemptr);
- RNA_string_set(&itemptr, "name", file->relpath);
- num_files++;
+ /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
+ if (!file->redirection_path) {
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
+ num_files++;
+ }
}
}
/* make sure the file specified in the filename button is added even if no
@@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
+ struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
+ if (file && file->redirection_path) {
+ /* redirection_path is an absolute path that takes precedence
+ * over using sfile->params->dir + sfile->params->file. */
+ BLI_split_dirfile(file->redirection_path,
+ sfile->params->dir,
+ sfile->params->file,
+ sizeof(sfile->params->dir),
+ sizeof(sfile->params->file));
+ /* Update relpath with redirected filename as well so that the alternative
+ * combination of sfile->params->dir + relpath remains valid as well. */
+ MEM_freeN(file->relpath);
+ file->relpath = BLI_strdup(sfile->params->file);
+ }
+
/* directory change */
if (file && (file->typeflag & FILE_TYPE_DIR)) {
if (!file->relpath) {
@@ -1634,9 +1651,6 @@ static int file_exec(bContext *C, wmOperator *exec_op)
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
BLI_path_slash_ensure(sfile->params->dir);
}
- if (file->redirection_path) {
- STRNCPY(sfile->params->dir, file->redirection_path);
- }
ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 7f6d0658ec8..d8d7ef01a2e 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
/* If this path is in System list or path cache then use that icon. */
struct FSMenu *fsmenu = ED_fsmenu_get();
FSMenuCategory categories[] = {
+ FS_CATEGORY_SYSTEM,
FS_CATEGORY_SYSTEM_BOOKMARKS,
FS_CATEGORY_OTHER,
};
@@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file,
for (int i = 0; i < ARRAY_SIZE(categories); i++) {
FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
char fullpath[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
- BLI_path_slash_ensure(fullpath);
+ char *target = fullpath;
+ if (file->redirection_path) {
+ target = file->redirection_path;
+ }
+ else {
+ BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_path_slash_ensure(fullpath);
+ }
for (; tfsm; tfsm = tfsm->next) {
- if (STREQ(tfsm->path, fullpath)) {
+ if (STREQ(tfsm->path, target)) {
/* Never want a little folder inside a large one. */
return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
}
@@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
}
}
- if (file->attributes & FILE_ATTR_ANY_LINK) {
- return ICON_LOOP_FORWARDS;
- }
- else if (file->attributes & FILE_ATTR_OFFLINE) {
+ if (file->attributes & FILE_ATTR_OFFLINE) {
return ICON_ERROR;
}
else if (file->attributes & FILE_ATTR_TEMPORARY) {
@@ -1375,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) {
FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+
preview->index = index;
preview->flags = entry->typeflag;
preview->img = NULL;
@@ -2270,13 +2281,6 @@ int ED_path_extension_type(const char *path)
return 0;
}
-static int file_extension_type(const char *dir, const char *relpath)
-{
- char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return ED_path_extension_type(path);
-}
-
int ED_file_extension_icon(const char *path)
{
const int type = ED_path_extension_type(path);
@@ -2475,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root,
{
struct direntry *files;
int nbr_files, nbr_entries = 0;
- char path[FILE_MAX];
+ /* Full path of the item. */
+ char full_path[FILE_MAX];
nbr_files = BLI_filelist_dir_contents(root, &files);
if (files) {
@@ -2491,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root,
entry->relpath = MEM_dupallocN(files[i].relname);
entry->st = files[i].s;
- BLI_join_dirfile(path, sizeof(path), root, entry->relpath);
+ BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
+ char *target = full_path;
- /* Set file type. */
+ /* Set initial file type and attributes. */
+ entry->attributes = BLI_file_attributes(full_path);
if (S_ISDIR(files[i].s.st_mode)) {
entry->typeflag = FILE_TYPE_DIR;
}
- else if (do_lib && BLO_has_bfile_extension(entry->relpath)) {
- /* If we are considering .blend files as libs, promote them to directory status. */
- entry->typeflag = FILE_TYPE_BLENDER;
- /* prevent current file being used as acceptable dir */
- if (BLI_path_cmp(main_name, path) != 0) {
- entry->typeflag |= FILE_TYPE_DIR;
- }
- }
- /* Otherwise, do not check extensions for directories! */
- else if (!(entry->typeflag & FILE_TYPE_DIR)) {
- entry->typeflag = file_extension_type(root, entry->relpath);
- if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) {
- entry->typeflag |= FILE_TYPE_OPERATOR;
- }
- }
- /* Set file attributes. */
- entry->attributes = BLI_file_attributes(path);
+ /* Is this a file that points to another file? */
if (entry->attributes & FILE_ATTR_ALIAS) {
entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
- if (BLI_file_alias_target(entry->redirection_path, path)) {
+ if (BLI_file_alias_target(entry->redirection_path, full_path)) {
if (BLI_is_dir(entry->redirection_path)) {
entry->typeflag = FILE_TYPE_DIR;
+ BLI_path_slash_ensure(entry->redirection_path);
}
- else
+ else {
entry->typeflag = ED_path_extension_type(entry->redirection_path);
+ }
+ target = entry->redirection_path;
+#ifdef WIN32
+ /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
+#endif
+ }
+ else {
+ MEM_freeN(entry->redirection_path);
+ entry->redirection_path = NULL;
+ entry->attributes |= FILE_ATTR_HIDDEN;
+ }
+ }
+
+ if (!(entry->typeflag & FILE_TYPE_DIR)) {
+ if (do_lib && BLO_has_bfile_extension(target)) {
+ /* If we are considering .blend files as libs, promote them to directory status. */
+ entry->typeflag = FILE_TYPE_BLENDER;
+ /* prevent current file being used as acceptable dir */
+ if (BLI_path_cmp(main_name, target) != 0) {
+ entry->typeflag |= FILE_TYPE_DIR;
+ }
+ }
+ else {
+ entry->typeflag = ED_path_extension_type(target);
+ if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
+ entry->typeflag |= FILE_TYPE_OPERATOR;
+ }
}
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 66157296064..b03df01a02b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -418,7 +418,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
else {
/* if we're bookmarking this, file should come
* before the last separator, only automatically added
- * current dir go after the last sep. */
+ * current dir go after the last separator. */
if (flag & FS_INSERT_SAVE) {
break;
}
@@ -848,6 +848,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(volEnum);
+ /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15.
+ * Will have to find a new method to sync the Finder Favorites with File Browser. */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
@@ -891,6 +895,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(pathesArray);
CFRelease(list);
}
+# pragma GCC diagnostic pop
}
# else
/* unix */
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index ca8919f51a6..185bf029f1a 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -423,8 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
-
- uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -435,16 +434,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 1,
+ 0,
0,
0,
-1,
-1,
NULL);
- UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
- UI_but_unit_type_set(but, unit);
- uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -455,21 +452,42 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 0,
+ 1,
0,
0,
-1,
-1,
NULL);
UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
+
+ UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
}
/* previous handle - only if previous was Bezier interpolation */
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE);
+ but = uiDefButR(block,
+ UI_BTYPE_MENU,
+ B_REDR,
+ NULL,
+ 0,
+ 0,
+ but_max_width,
+ UI_UNIT_Y,
+ &bezt_ptr,
+ "handle_left_type",
+ 0,
+ 0,
+ 0,
+ -1,
+ -1,
+ "Type of left handle");
+ UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -488,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -507,8 +525,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
+ }
+
+ /* next handle - only if current is Bezier interpolation */
+ if (bezt->ipo == BEZT_IPO_BEZ) {
+ /* NOTE: special update callbacks are needed on the coords here due to T39911 */
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
@@ -518,22 +542,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
but_max_width,
UI_UNIT_Y,
&bezt_ptr,
- "handle_left_type",
+ "handle_right_type",
0,
0,
0,
-1,
-1,
- "Type of left handle");
+ "Type of right handle");
UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- }
- /* next handle - only if current is Bezier interpolation */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- /* NOTE: special update callbacks are needed on the coords here due to T39911 */
-
- col = uiLayoutColumn(layout, true);
- uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -552,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -571,25 +589,6 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
-
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
- but = uiDefButR(block,
- UI_BTYPE_MENU,
- B_REDR,
- NULL,
- 0,
- 0,
- but_max_width,
- UI_UNIT_Y,
- &bezt_ptr,
- "handle_right_type",
- 0,
- 0,
- 0,
- -1,
- -1,
- "Type of right handle");
- UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
}
}
else {
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index eb97077f77a..8cb85ce9800 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -885,7 +885,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene;
ViewLayer *view_layer;
Object *obedit;
- Image *ima;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -894,15 +893,13 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
view_layer = CTX_data_view_layer(C);
obedit = CTX_data_edit_object(C);
- ima = ED_space_image(sima);
-
/* get bounds */
float min[2], max[2];
if (ED_space_image_show_uvedit(sima, obedit)) {
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- bool success = ED_uvedit_minmax_multi(scene, ima, objects, objects_len, min, max);
+ bool success = ED_uvedit_minmax_multi(scene, objects, objects_len, min, max);
MEM_freeN(objects);
if (!success) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index eb1c46240cb..5668b88826e 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -225,9 +225,9 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
"PaintTile.mask");
}
- ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
- square_i(ED_IMAGE_UNDO_TILE_SIZE),
- "PaintTile.rect");
+ ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ square_i(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
ptile->use_float = has_float;
ptile->valid = true;
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 2a3f6d6e365..3685e5de852 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -141,7 +141,6 @@ static int report_textview_begin(TextViewContext *tvc)
{
const ReportList *reports = tvc->arg2;
- tvc->lheight = 14 * UI_DPI_FAC;
tvc->sel_start = 0;
tvc->sel_end = 0;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index f8c0e66873f..e1937dffb37 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -414,17 +414,11 @@ static const char *footer_string(ViewLayer *view_layer)
size_t ofs = 0;
uintptr_t mem_in_use = MEM_get_memory_in_use();
- uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use();
/* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
- if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
- BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
- }
-
if (GPU_mem_stats_supported()) {
int gpu_free_mem, gpu_tot_memory;
@@ -444,7 +438,7 @@ static const char *footer_string(ViewLayer *view_layer)
"%s%s | %s",
memstr,
gpumemstr,
- versionstr);
+ BKE_blender_version_string());
return view_layer->footer_str;
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index c842fa8b4ac..8076d3d7eaf 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -394,25 +394,26 @@ int textview_draw(TextViewContext *tvc,
tvc->line_get(tvc, &ext_line, &ext_len);
- if (!textview_draw_string(&tds,
- ext_line,
- ext_len,
- (data_flag & TVC_LINE_FG) ? fg : NULL,
- (data_flag & TVC_LINE_BG) ? bg : NULL,
- (data_flag & TVC_LINE_ICON) ? icon : 0,
- (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
- (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
- bg_sel)) {
- /* When drawing, if we pass v2d->cur.ymax, then quit. */
- if (do_draw) {
- /* Past the y limits. */
- break;
- }
- }
+ const bool is_out_of_view_y = !textview_draw_string(
+ &tds,
+ ext_line,
+ ext_len,
+ (data_flag & TVC_LINE_FG) ? fg : NULL,
+ (data_flag & TVC_LINE_BG) ? bg : NULL,
+ (data_flag & TVC_LINE_ICON) ? icon : 0,
+ (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
+ (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
+ bg_sel);
if (do_draw) {
+ /* We always want the cursor to draw. */
if (tvc->draw_cursor && iter_index == 0) {
- tvc->draw_cursor(tvc, tds.cwidth, tds.columns, tds.lofs);
+ tvc->draw_cursor(tvc, tds.cwidth, tds.columns);
+ }
+
+ /* When drawing, if we pass v2d->cur.ymax, then quit. */
+ if (is_out_of_view_y) {
+ break;
}
}
@@ -428,6 +429,11 @@ int textview_draw(TextViewContext *tvc,
tvc->end(tvc);
+ /* Sanity checks (bugs here can be tricky to track down). */
+ BLI_assert(tds.lheight == tvc->lheight);
+ BLI_assert(tds.row_vpadding == tvc->row_vpadding);
+ BLI_assert(tds.do_draw == do_draw);
+
xy[1] += tvc->lheight * 2;
return xy[1] - y_orig;
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 8eef4ef5d56..41f8baf634e 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -60,7 +60,7 @@ typedef struct TextViewContext {
int *r_icon,
uchar r_icon_fg[4],
uchar r_icon_bg[4]);
- void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender);
+ void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns);
/* constant theme colors */
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
const void *iter;
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 1d73937d762..95a37f85828 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -82,7 +82,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, NULL);
snode_update(snode, node);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index bd5ce135f82..ac58ec1e636 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -648,9 +648,12 @@ void snode_update(SpaceNode *snode, bNode *node)
}
}
-void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
+void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
{
const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = false;
+ }
nodeSetActive(ntree, node);
@@ -719,6 +722,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = true;
+ }
ED_node_tag_update_nodetree(bmain, ntree, node);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -1290,7 +1296,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
newnode = node->new_node;
nodeSetSelected(node, false);
- node->flag &= ~NODE_ACTIVE;
+ node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 9eabcc44d80..06f568c80f3 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include "DNA_node_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
@@ -36,10 +37,12 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -57,6 +60,36 @@
#include "node_intern.h" /* own include */
+/* Function to detect if there is a visible view3d that uses workbench in texture mode.
+ * This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
+ * the depsgraph that can be used by the draw engines to check if they need to be redrawn.
+ *
+ * We don't want to add these risky changes this close before releasing 2.83 without good testing
+ * hence this workaround. There are still cases were too many updates happen. For example when you
+ * have both a Cycles and workbench with textures viewport.
+ * */
+static bool has_workbench_in_texture_color(const wmWindowManager *wm,
+ const Scene *scene,
+ const Object *ob)
+{
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ if (win->scene != scene) {
+ continue;
+ }
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ const View3D *v3d = area->spacedata.first;
+
+ if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public Node Selection API
* \{ */
@@ -415,6 +448,10 @@ void node_select_single(bContext *C, bNode *node)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ bool active_texture_changed = false;
bNode *tnode;
for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) {
@@ -424,10 +461,13 @@ void node_select_single(bContext *C, bNode *node)
}
nodeSetSelected(node, true);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
@@ -440,6 +480,9 @@ static int node_mouse_select(bContext *C,
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
bNode *node, *tnode;
bNodeSocket *sock = NULL;
bNodeSocket *tsock;
@@ -546,12 +589,15 @@ static int node_mouse_select(bContext *C,
/* update node order */
if (ret_value != OPERATOR_CANCELLED) {
+ bool active_texture_changed = false;
if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) {
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
}
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 740d090e641..e879e01ecc4 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -209,6 +209,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
break;
@@ -354,6 +355,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op))
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 13cbda5aad7..7d3b95721c6 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -178,20 +178,13 @@ static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2)
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
}
-static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
- bArmature *arm = (bArmature *)poin;
- Bone *bone = (Bone *)poin2;
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
+ Bone *bone = (Bone *)poin;
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
-
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
}
static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
@@ -859,6 +852,7 @@ typedef struct RestrictProperties {
*layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
+ PropertyRNA *bone_hide_viewport;
} RestrictProperties;
/* We don't care about the value of the property
@@ -877,6 +871,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_viewport;
bool modifier_show_render;
bool constraint_enable;
+ bool bone_hide_viewport;
} RestrictPropertiesActive;
static void outliner_restrict_properties_enable_collection_set(
@@ -1011,6 +1006,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
+ props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide");
+
props.initialized = true;
}
@@ -1279,27 +1276,32 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
else if (tselem->type == TSE_POSE_CHANNEL) {
+ PointerRNA ptr;
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
+ bArmature *arm = ob->data;
+
+ RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
- bt = uiDefIconButBitI(block,
- UI_BTYPE_ICON_TOGGLE,
- BONE_HIDDEN_P,
- 0,
- ICON_RESTRICT_VIEW_OFF,
- (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- &(bone->flag),
- 0,
- 0,
- 0,
- 0,
- TIP_("Restrict visibility in the 3D View"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
+ bt = uiDefIconButR_prop(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ 0,
+ (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &ptr,
+ props.bone_hide_viewport,
+ -1,
+ 0,
+ 0,
+ -1,
+ -1,
+ TIP_("Restrict visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_bone_visibility_cb, bone, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 97ce9ad549f..3db75d9288b 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -460,6 +460,9 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->invoke = outliner_item_rename;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -578,6 +581,9 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
ot->invoke = outliner_id_delete_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -715,7 +721,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
ot->exec = outliner_id_remap_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
@@ -823,6 +830,7 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot)
ot->exec = outliner_id_copy_exec;
ot->poll = ED_operator_outliner_active;
+ /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
ot->flag = 0;
}
@@ -863,7 +871,8 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot)
ot->exec = outliner_id_paste_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -974,6 +983,9 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = outliner_lib_relocate_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* XXX This does not work with several items
@@ -1028,6 +1040,9 @@ void OUTLINER_OT_lib_reload(wmOperatorType *ot)
ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void lib_reload_cb(bContext *C,
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 0ccf982fd29..6b65167a921 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -1450,7 +1450,8 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- str = "Remap ID";
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick
+ * does not work here). */
}
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
@@ -1481,7 +1482,9 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
ED_outliner_select_sync_from_object_tag(C);
}
- ED_undo_push(C, str);
+ if (str != NULL) {
+ ED_undo_push(C, str);
+ }
return OPERATOR_FINISHED;
}
@@ -1681,6 +1684,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -1801,16 +1805,22 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
if (idlevel > 0) {
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- ED_undo_push(C, "Remap");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
}
break;
}
case OUTLINER_IDOP_COPY: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
+ /* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
break;
@@ -1929,7 +1939,6 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_LIB_RENAME: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
@@ -1944,16 +1953,17 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
break;
}
case OL_LIB_RELOCATE: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
- ED_undo_push(C, "Relocate Library");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
default:
@@ -2102,7 +2112,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag = 0;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
// TODO: this would be nicer as an ID-pointer...
@@ -2150,6 +2160,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_AnimDataOps event;
@@ -2178,7 +2189,10 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ wm->op_undo_depth--;
+ ED_undo_push(C, "Set active action");
break;
case OUTLINER_ANIMOP_CLEAR_ACT:
@@ -2474,6 +2488,7 @@ static int do_outliner_operation_event(
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(region);
+ ED_outliner_select_sync_from_outliner(C, soops);
}
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index c910f1d2382..232bb1d66e8 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1652,10 +1652,10 @@ static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %s"), num_str);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %s"), num_str);
}
else {
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %d"), offset);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %d"), offset);
}
}
@@ -2508,7 +2508,7 @@ static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
- return WM_operator_confirm(C, op, event);
+ return sequencer_delete_exec(C, op);
}
void SEQUENCER_OT_delete(wmOperatorType *ot)
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 0ab8f285de9..9ae501dc060 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
view3d_header.c
view3d_iterators.c
view3d_ops.c
+ view3d_placement.c
view3d_project.c
view3d_select.c
view3d_snap.c
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 7fcd881d481..74c6692337e 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -675,6 +675,8 @@ static void view3d_widgets(void)
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
WM_gizmotype_append(VIEW3D_GT_ruler_item);
+ WM_gizmogrouptype_append(VIEW3D_GGT_placement);
+
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
}
@@ -1087,9 +1089,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
}
}
+/* concept is to retrieve cursor type context-less */
static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- if (!WM_cursor_set_from_tool(win, area, region)) {
+ if (WM_cursor_set_from_tool(win, area, region)) {
+ return;
+ }
+
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
+ WM_cursor_set(win, WM_CURSOR_EDIT);
+ }
+ else {
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 18425b88047..f81b4bb09e2 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1577,9 +1577,7 @@ static void view3d_panel_transform(const bContext *C, Panel *panel)
}
else {
View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
- v3d_editvertex_buts(col, v3d, ob, lim);
+ v3d_editvertex_buts(col, v3d, ob, FLT_MAX);
}
}
else if (ob->mode & OB_MODE_POSE) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 5cdf6ce28cb..25678820050 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -5018,7 +5018,6 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float cursor_co[3],
float cursor_quat[4])
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
@@ -5052,7 +5051,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float ray_co[3];
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, scene, 0, region, v3d);
+ scene, 0, region, v3d);
float obmat[4][4];
Object *ob_dummy = NULL;
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index 3301e28c90c..3ce4c8dc9a8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -536,9 +536,12 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
return -1;
}
-static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz))
+static int gizmo_axis_cursor_get(wmGizmo *gz)
{
- return WM_CURSOR_DEFAULT;
+ if (gz->highlight_part > 0) {
+ return WM_CURSOR_EDIT;
+ }
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index e4863c0cdeb..f3bc0a8a15b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -40,6 +40,7 @@
#include "DNA_object_types.h"
#include "DNA_view3d_types.h"
+#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -57,10 +58,13 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "DEG_depsgraph_query.h"
+
#include "view3d_intern.h" /* own include */
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BLF_api.h"
@@ -94,10 +98,6 @@ enum {
RULER_STATE_DRAG,
};
-enum {
- RULER_SNAP_OK = (1 << 0),
-};
-
struct RulerItem;
typedef struct RulerInfo {
@@ -106,19 +106,25 @@ typedef struct RulerInfo {
int snap_flag;
int state;
- struct SnapObjectContext *snap_context;
-
/* wm state */
+ wmWindowManager *wm;
wmWindow *win;
ScrArea *area;
ARegion *region; /* re-assigned every modal update */
/* Track changes in state. */
struct {
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
bool do_snap;
+#endif
bool do_thickness;
} drag_state_prev;
+ struct {
+ wmGizmo *gizmo;
+ PropertyRNA *prop_prevpoint;
+ } snap_data;
+
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -269,26 +275,17 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
* Ensure the 'snap_context' is only cached while dragging,
* needed since the user may toggle modes between tool use.
*/
-static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+static void ruler_state_set(RulerInfo *ruler_info, int state)
{
- Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
- /* always remove */
- if (ruler_info->snap_context) {
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
- ruler_info->snap_context = NULL;
- }
-
if (state == RULER_STATE_NORMAL) {
/* pass */
}
else if (state == RULER_STATE_DRAG) {
memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev));
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, ruler_info->region, CTX_wm_view3d(C));
}
else {
BLI_assert(0);
@@ -307,13 +304,18 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
RulerInfo *ruler_info,
RulerItem *ruler_item,
const int mval[2],
- const bool do_thickness,
- const bool do_snap)
+ const bool do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ const bool do_snap
+#endif
+)
{
+ wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo;
const float eps_bias = 0.0002f;
float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true);
if (ruler_item) {
RulerInteraction *inter = ruler_item->gz.interaction_data;
@@ -322,8 +324,10 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
copy_v3_v3(co, inter->drag_start_co);
view3d_ruler_item_project(ruler_info, co, mval);
if (do_thickness && inter->co_index != 1) {
- // Scene *scene = CTX_data_scene(C);
- // View3D *v3d = ruler_info->area->spacedata.first;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ View3D *v3d = ruler_info->area->spacedata.first;
+ SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(
+ scene, ruler_info->region, v3d, snap_gizmo);
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -331,7 +335,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
- if (ED_transform_snap_object_project_view3d(ruler_info->snap_context,
+ if (ED_transform_snap_object_project_view3d(snap_context,
depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
@@ -346,7 +350,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
negate_v3(ray_normal);
/* add some bias */
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
- ED_transform_snap_object_project_ray(ruler_info->snap_context,
+ ED_transform_snap_object_project_ray(snap_context,
depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -359,7 +363,12 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
NULL);
}
}
- else if (do_snap) {
+ else
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (do_snap)
+#endif
+ {
+ View3D *v3d = ruler_info->area->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
float *prev_point = NULL;
@@ -374,23 +383,16 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
prev_point = ruler_item->co[0];
}
}
+ if (prev_point != NULL) {
+ RNA_property_float_set_array(
+ snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
- if (ED_transform_snap_object_project_view3d(
- ruler_info->snap_context,
- depsgraph,
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR),
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
- .use_occlusion_test = true,
- },
- mval_fl,
- prev_point,
- &dist_px,
- co,
- NULL)) {
- ruler_info->snap_flag |= RULER_SNAP_OK;
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL);
+
+ if (snap_elem) {
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false);
}
}
return true;
@@ -417,6 +419,15 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
return NULL;
}
+static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup)
+{
+#ifndef NDEBUG
+ RulerInfo *ruler_info = gzgroup->customdata;
+ BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo);
+#endif
+ return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
{
@@ -448,7 +459,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
- for (ruler_item = gzgroup->gizmos.first; ruler_item;
+ for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
ruler_item = (RulerItem *)ruler_item->gz.next) {
bGPDspoint *pt;
int j;
@@ -556,6 +567,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
uchar color_wire[3];
float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
+ /* Pixel Space. */
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ wmOrtho2_region_pixelspace(region);
+
/* anti-aliased lines for more consistent appearance */
GPU_line_smooth(true);
GPU_line_width(1.0f);
@@ -575,20 +592,30 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
const bool is_act = (ruler_info->item_active == ruler_item);
float dir_ruler[2];
float co_ss[3][2];
+ bool proj_ok[3];
int j;
- /* should these be checked? - ok for now not to */
+ /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */
for (j = 0; j < 3; j++) {
- ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ eV3DProjStatus status = ED_view3d_project_float_global(
+ region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR);
+ proj_ok[j] = (status == V3D_PROJ_RET_OK);
}
+ /* 3d drawing. */
+
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
GPU_blend(true);
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint shdr_pos_3d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -605,21 +632,20 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, 3);
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[1]);
- immVertex2fv(shdr_pos, co_ss[2]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[1]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
immEnd();
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* arc */
{
float dir_tmp[3];
- float co_tmp[3];
- float arc_ss_coord[2];
+ float ar_coord[3];
float dir_a[3];
float dir_b[3];
@@ -648,16 +674,53 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
for (j = 0; j <= arc_steps; j++) {
- madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
- ED_view3d_project_float_global(region, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
+ madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale);
mul_qt_v3(quat, dir_tmp);
- immVertex2fv(shdr_pos, arc_ss_coord);
+ immVertex3fv(shdr_pos_3d, ar_coord);
}
immEnd();
}
+ immUnbindProgram();
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv(
+ "colors",
+ (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
+ 2);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* 2d drawing. */
+
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+
+ const uint shdr_pos_2d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* capping */
{
float rot_90_vec_a[2];
@@ -676,15 +739,15 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
GPU_blend(true);
- if (is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
+ if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
GPU_line_width(3.0f);
immUniformColor3fv(color_act);
immBegin(GPU_PRIM_LINES, 4);
/* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
immEnd();
GPU_line_width(1.0f);
@@ -692,25 +755,33 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 8);
+ if (proj_ok[0] || proj_ok[2] || proj_ok[1]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- /* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ /* angle vertex */
+ if (proj_ok[1]) {
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -729,10 +800,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
/* draw text (bg) */
- {
+ if (proj_ok[1]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -743,7 +814,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[1]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_rotation(blf_mono_font, 0.0f);
@@ -751,30 +822,6 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
}
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 2); /* "advanced" mode */
- const float *col = is_act ? color_act : color_base;
- immUniformArray4fv(
- "colors",
- (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
- 2);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
-
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[2]);
-
- immEnd();
-
- immUnbindProgram();
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
@@ -790,19 +837,25 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 4);
+ if (proj_ok[0] || proj_ok[2]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -824,10 +877,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] -= numstr_size[1] / 2.0f;
/* draw text (bg) */
- {
+ if (proj_ok[0] && proj_ok[2]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -838,7 +891,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[0] && proj_ok[2]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_draw(blf_mono_font, numstr, sizeof(numstr));
@@ -849,27 +902,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
BLF_disable(blf_mono_font, BLF_ROTATION);
-#undef ARC_STEPS
-
- /* draw snap */
- if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG) &&
- (ruler_item->gz.interaction_data != NULL)) {
- RulerInteraction *inter = ruler_item->gz.interaction_data;
- /* size from drawSnapping */
- const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- float co_ss_snap[3];
- ED_view3d_project_float_global(
- region, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP);
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor3(TH_GIZMO_VIEW_ALIGN);
-
- imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32);
-
- immUnbindProgram();
- }
+#undef ARC_STEPS
}
static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
@@ -902,35 +938,36 @@ static int gizmo_ruler_modal(bContext *C,
RulerInfo *ruler_info = gz->parent_gzgroup->customdata;
RulerItem *ruler_item = (RulerItem *)gz;
ARegion *region = CTX_wm_region(C);
- bool do_cursor_update = false;
+ bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE);
ruler_info->region = region;
- switch (event->type) {
- case MOUSEMOVE: {
- do_cursor_update = true;
- break;
- }
- }
-
- const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP;
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
+#endif
const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE;
- if ((ruler_info->drag_state_prev.do_snap != do_snap) ||
- (ruler_info->drag_state_prev.do_thickness != do_thickness)) {
+ if ((ruler_info->drag_state_prev.do_thickness != do_thickness)) {
do_cursor_update = true;
}
if (do_cursor_update) {
if (ruler_info->state == RULER_STATE_DRAG) {
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- if (view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) {
+ if (view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ do_snap
+#endif
+ )) {
do_draw = true;
}
}
}
- ruler_info->drag_state_prev.do_snap = do_snap;
ruler_info->drag_state_prev.do_thickness = do_thickness;
if (do_draw) {
@@ -957,7 +994,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* Add Center Point */
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
inter->co_index = 1;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -978,13 +1015,21 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* update the new location */
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item_pick, event->mval, false, false);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item_pick,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ false
+#endif
+ );
}
}
else {
inter->co_index = gz->highlight_part;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]);
@@ -997,6 +1042,28 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE;
}
+ {
+ /* Set Snap prev point. */
+ float *prev_point;
+ if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) {
+ prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL;
+ }
+ else if (inter->co_index == 0) {
+ prev_point = ruler_item_pick->co[2];
+ }
+ else {
+ prev_point = ruler_item_pick->co[0];
+ }
+
+ if (prev_point) {
+ RNA_property_float_set_array(
+ ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
+ else {
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ }
+ }
+
ruler_info->item_active = ruler_item_pick;
return OPERATOR_RUNNING_MODAL;
@@ -1009,10 +1076,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
if (!cancel) {
if (ruler_info->state == RULER_STATE_DRAG) {
- if (ruler_info->snap_flag & RULER_SNAP_OK) {
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
- }
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false);
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
/* We could convert only the current gizmo, for now just re-generate. */
view3d_ruler_to_gpencil(C, gzgroup);
@@ -1022,7 +1088,7 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
MEM_SAFE_FREE(gz->interaction_data);
}
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
static int gizmo_ruler_cursor_get(wmGizmo *gz)
@@ -1059,16 +1125,39 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__);
+ wmGizmo *gizmo;
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
+ WM_gizmo_operator_set(gizmo, 0, ot, NULL);
+ }
+
if (view3d_ruler_from_gpencil(C, gzgroup)) {
/* nop */
}
+ wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
+
+ ruler_info->wm = wm;
ruler_info->win = win;
ruler_info->area = area;
ruler_info->region = region;
+ ruler_info->snap_data.gizmo = gizmo;
+ ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point");
gzgroup->customdata = ruler_info;
}
@@ -1078,7 +1167,7 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt)
gzgt->name = "Ruler Widgets";
gzgt->idname = view3d_gzgt_ruler_id;
- gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -1132,8 +1221,20 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* snap the first point added, not essential but handy */
inter->co_index = 0;
- view3d_ruler_item_mousemove(depsgraph, ruler_info, ruler_item, event->mval, false, true);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ true
+#endif
+ );
copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
+ RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr,
+ ruler_info->snap_data.prop_prevpoint,
+ inter->drag_start_co);
}
else {
negate_v3_v3(inter->drag_start_co, rv3d->ofs);
@@ -1152,6 +1253,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Ruler Add";
ot->idname = "VIEW3D_OT_ruler_add";
+ ot->description = "Add ruler";
ot->invoke = view3d_ruler_add_invoke;
ot->poll = view3d_ruler_poll;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index c16131c8317..50cd71d7edc 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
+void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
@@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
+/* view3d_placement.c */
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot);
+
/* space_view3d.c */
extern const char *view3d_context_dir[]; /* doc access */
@@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot);
void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt);
+void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt);
+
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
* without this define we get the old behavior which is to try and align them
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 08e68c9174e..91e629147f4 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -126,7 +126,7 @@ void meshobject_foreachScreenVert(
Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph);
Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
- me = mesh_get_eval_deform(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -406,6 +406,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co_b[2]),
void *userData,
const eV3DProjTest clip_flag)
@@ -414,6 +415,8 @@ void nurbs_foreachScreenVert(ViewContext *vc,
Nurb *nu;
int i;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ /* If no point in the triple is selected, the handles are invisible. */
+ const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -427,15 +430,17 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BezTriple *bezt = &nu->bezt[i];
if (bezt->hide == 0) {
+ const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) &&
+ (!only_selected || BEZT_ISSEL_ANY(bezt));
float screen_co[2];
- if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (!handles_visible) {
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, false, screen_co);
}
}
else {
@@ -444,21 +449,21 @@ void nurbs_foreachScreenVert(ViewContext *vc,
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 0, screen_co);
+ func(userData, nu, NULL, bezt, 0, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[2],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 2, screen_co);
+ func(userData, nu, NULL, bezt, 2, true, screen_co);
}
}
}
@@ -473,7 +478,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
if (ED_view3d_project_float_object(
vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, bp, NULL, -1, screen_co);
+ func(userData, nu, bp, NULL, -1, false, screen_co);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 1ad3f8bb1f5..0770bac1313 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -211,6 +211,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
+ WM_operatortype_append(VIEW3D_OT_interactive_add);
+
WM_operatortype_append(VIEW3D_OT_toggle_shading);
WM_operatortype_append(VIEW3D_OT_toggle_xray);
WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
@@ -234,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf)
viewmove_modal_keymap(keyconf);
viewzoom_modal_keymap(keyconf);
viewdolly_modal_keymap(keyconf);
+ viewplace_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
new file mode 100644
index 00000000000..f2b78bc2aaf
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -0,0 +1,1153 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spview3d
+ *
+ * Operator to interactively place data.
+ *
+ * Currently only adds meshes, but could add other kinds of data
+ * including library assets & non-mesh types.
+ */
+
+#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "view3d_intern.h"
+
+static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
+
+/* -------------------------------------------------------------------- */
+/** \name Local Types
+ * \{ */
+
+enum ePlace_PrimType {
+ PLACE_PRIMITIVE_TYPE_CUBE = 1,
+ PLACE_PRIMITIVE_TYPE_CYLINDER = 2,
+ PLACE_PRIMITIVE_TYPE_CONE = 3,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5,
+};
+
+enum ePlace_Origin {
+ PLACE_ORIGIN_BASE = 1,
+ PLACE_ORIGIN_CENTER = 2,
+};
+
+enum ePlace_Depth {
+ PLACE_DEPTH_SURFACE = 1,
+ PLACE_DEPTH_CURSOR_PLANE = 2,
+ PLACE_DEPTH_CURSOR_VIEW = 3,
+};
+
+struct InteractivePlaceData {
+ /* Window manager variables (set these even when waiting for input). */
+ Scene *scene;
+ ScrArea *area;
+ View3D *v3d;
+ ARegion *region;
+
+ /** Draw object preview region draw callback. */
+ void *draw_handle_view;
+
+ float co_src[3];
+
+ /** Primary & secondary steps. */
+ struct {
+ bool is_centered;
+ bool is_fixed_aspect;
+ float plane[4];
+ float co_dst[3];
+ } step[2];
+
+ float matrix_orient[3][3];
+ int orient_axis;
+
+ /** The tool option, if we start centered, invert toggling behavior. */
+ bool is_centered_init;
+
+ bool use_snap, is_snap_found, is_snap_invert;
+ float snap_co[3];
+
+ /** Can index into #InteractivePlaceData.step. */
+ enum {
+ STEP_BASE = 0,
+ STEP_DEPTH = 1,
+ } step_index;
+
+ enum ePlace_PrimType primitive_type;
+
+ /** Activated from the tool-system. */
+ bool use_tool;
+
+ /** Event used to start the operator. */
+ short launch_event;
+
+ /** When activated without a tool. */
+ bool wait_for_input;
+
+ /** Optional snap gizmo, needed for snapping. */
+ wmGizmo *snap_gizmo;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+/* On-screen snap distance. */
+#define MVAL_MAX_PX_DIST 12.0f
+
+static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
+{
+ if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
+ PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location");
+ RNA_property_float_get_array(gz->ptr, prop_location, r_location);
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Drawing (Cube, Cone, Cylinder...)
+ * \{ */
+
+static void draw_line_loop(float coords[][3], int coords_len, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_pairs(float coords_a[][3],
+ float coords_b[][3],
+ int coords_len,
+ const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len * 2);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
+ GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_bounds(const BoundBox *bounds, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ int edges[12][2] = {
+ /* First side. */
+ {0, 1},
+ {1, 2},
+ {2, 3},
+ {3, 0},
+ /* Second side. */
+ {4, 5},
+ {5, 6},
+ {6, 7},
+ {7, 4},
+ /* Edges between. */
+ {0, 4},
+ {1, 5},
+ {2, 6},
+ {3, 7},
+ };
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2);
+
+ for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds)
+{
+ memset(bounds, 0x0, sizeof(*bounds));
+
+ if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
+ return false;
+ }
+
+ float matrix_orient_inv[3][3];
+ invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
+
+ const int x_axis = (ipd->orient_axis + 1) % 3;
+ const int y_axis = (ipd->orient_axis + 2) % 3;
+
+ float quad_base[4][3];
+ float quad_secondary[4][3];
+
+ copy_v3_v3(quad_base[0], ipd->co_src);
+ copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
+
+ /* Only set when we have a fixed aspect. */
+ float fixed_aspect_dimension;
+
+ /* *** Primary *** */
+
+ {
+ float delta_local[3];
+ float delta_a[3];
+ float delta_b[3];
+
+ sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
+ mul_m3_v3(matrix_orient_inv, delta_local);
+
+ copy_v3_v3(delta_a, delta_local);
+ copy_v3_v3(delta_b, delta_local);
+ delta_a[ipd->orient_axis] = 0.0f;
+ delta_b[ipd->orient_axis] = 0.0f;
+
+ delta_a[x_axis] = 0.0f;
+ delta_b[y_axis] = 0.0f;
+
+ /* Assign here in case secondary */
+ fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
+
+ if (ipd->step[0].is_fixed_aspect) {
+ delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
+ delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
+ }
+
+ mul_m3_v3(ipd->matrix_orient, delta_a);
+ mul_m3_v3(ipd->matrix_orient, delta_b);
+
+ if (ipd->step[0].is_fixed_aspect) {
+ /* Recalculate the destination point. */
+ copy_v3_v3(quad_base[2], ipd->co_src);
+ add_v3_v3(quad_base[2], delta_a);
+ add_v3_v3(quad_base[2], delta_b);
+ }
+
+ add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
+ add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
+ }
+
+ if (ipd->step[0].is_centered) {
+ /* Use a copy in case aspect was applied to the quad. */
+ float base_co_dst[3];
+ copy_v3_v3(base_co_dst, quad_base[2]);
+ for (int i = 0; i < 4; i++) {
+ sub_v3_v3(quad_base[i], base_co_dst);
+ mul_v3_fl(quad_base[i], 2.0f);
+ add_v3_v3(quad_base[i], base_co_dst);
+ }
+ }
+
+ /* *** Secondary *** */
+
+ float delta_local[3];
+ if (ipd->step_index == STEP_DEPTH) {
+ sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
+ }
+ else {
+ zero_v3(delta_local);
+ }
+
+ if (ipd->step[1].is_fixed_aspect) {
+ if (!is_zero_v3(delta_local)) {
+ normalize_v3_length(delta_local, fixed_aspect_dimension);
+ }
+ }
+
+ if (ipd->step[1].is_centered) {
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ sub_v3_v3(quad_base[i], delta_local);
+ }
+ mul_v3_fl(delta_local, 2.0f);
+ }
+
+ if ((ipd->step_index == STEP_DEPTH) &&
+ (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) {
+
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
+ }
+ }
+ else {
+ copy_v3_v3(quad_secondary[0], quad_base[0]);
+ copy_v3_v3(quad_secondary[1], quad_base[1]);
+ copy_v3_v3(quad_secondary[2], quad_base[2]);
+ copy_v3_v3(quad_secondary[3], quad_base[3]);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(bounds->vec[i], quad_base[i]);
+ copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
+ }
+
+ return true;
+}
+
+static void draw_circle_in_quad(const float v1[2],
+ const float v2[2],
+ const float v3[2],
+ const float v4[2],
+ const int resolution,
+ const float color[4])
+{
+ /* This isn't so efficient. */
+ const float quad[4][2] = {
+ {-1, -1},
+ {+1, -1},
+ {+1, +1},
+ {-1, +1},
+ };
+
+ float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__);
+ for (int i = 0; i <= resolution; i++) {
+ float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f;
+ float x = cosf(theta);
+ float y = sinf(theta);
+ float pt[2] = {x, y};
+ float w[4];
+ barycentric_weights_v2_quad(UNPACK4(quad), pt, w);
+
+ float *co = coords[i];
+ zero_v3(co);
+ madd_v3_v3fl(co, v1, w[0]);
+ madd_v3_v3fl(co, v2, w[1]);
+ madd_v3_v3fl(co, v3, w[2]);
+ madd_v3_v3fl(co, v4, w[3]);
+ }
+ draw_line_loop(coords, resolution + 1, color);
+ MEM_freeN(coords);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Callbacks
+ * \{ */
+
+static void draw_primitive_view_impl(const struct bContext *C,
+ struct InteractivePlaceData *ipd,
+ const float color[4])
+{
+ UNUSED_VARS(C);
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+ draw_line_bounds(&bounds, color);
+
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ /* pass */
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+ draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+
+ float center[3];
+ mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4])));
+
+ float coords_a[4][3];
+ float coords_b[4][3];
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(coords_a[i], center);
+ mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
+ }
+
+ draw_line_pairs(coords_a, coords_b, 4, color);
+ }
+ else if (ELEM(ipd->primitive_type,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) {
+ /* See bound-box diagram for reference. */
+
+ /* Primary Side. */
+ float v01[3], v12[3], v23[3], v30[3];
+ mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
+ mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
+ mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
+ mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
+ /* Secondary Side. */
+ float v45[3], v56[3], v67[3], v74[3];
+ mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
+ mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
+ mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
+ mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
+ /* Edges between. */
+ float v04[3], v15[3], v26[3], v37[3];
+ mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
+ mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
+ mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
+ mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
+
+ draw_circle_in_quad(v01, v45, v67, v23, 32, color);
+ draw_circle_in_quad(v30, v12, v56, v74, 32, color);
+ draw_circle_in_quad(v04, v15, v26, v37, 32, color);
+ }
+}
+
+static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg)
+{
+ struct InteractivePlaceData *ipd = arg;
+ float color[4];
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color);
+
+ const bool use_depth = !XRAY_ENABLED(ipd->v3d);
+ const bool depth_test_enabled = GPU_depth_test_enabled();
+
+ if (use_depth) {
+ GPU_depth_test(false);
+ color[3] = 0.15f;
+ draw_primitive_view_impl(C, ipd, color);
+ }
+
+ if (use_depth) {
+ GPU_depth_test(true);
+ }
+ color[3] = 1.0f;
+ draw_primitive_view_impl(C, ipd, color);
+
+ if (use_depth) {
+ if (depth_test_enabled == false) {
+ GPU_depth_test(false);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Object Modal Operator
+ * \{ */
+
+/**
+ *
+ * */
+static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
+{
+
+ const int plane_axis = RNA_enum_get(op->ptr, "plane_axis");
+ const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
+ const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin");
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ RegionView3D *rv3d = ipd->region->regiondata;
+
+ ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
+
+ ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
+
+ ipd->orient_axis = plane_axis;
+ ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
+ ipd->step[0].is_centered = ipd->is_centered_init;
+ ipd->step[1].is_centered = ipd->is_centered_init;
+ ipd->step_index = STEP_BASE;
+
+ /* Assign snap gizmo which is may be used as part of the tool. */
+ {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
+ if ((gzgroup != NULL) && gzgroup->gizmos.first) {
+ ipd->snap_gizmo = gzgroup->gizmos.first;
+ }
+ }
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ ipd->primitive_type = RNA_property_enum_get(op->ptr, prop);
+ ipd->use_tool = false;
+ }
+ else {
+ ipd->use_tool = true;
+
+ /* Get from the tool, a bit of a non-standard way of operating. */
+ const bToolRef *tref = ipd->area->runtime.tool;
+ if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO;
+ }
+ else {
+ /* If the user runs this as an operator they should set the 'primitive_type',
+ * however running from operator search will end up at this point. */
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ ipd->use_tool = false;
+ }
+ }
+ }
+
+ UNUSED_VARS(C, event);
+
+ ipd->draw_handle_view = ED_region_draw_cb_activate(
+ ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW);
+
+ ED_region_tag_redraw(ipd->region);
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ const bool is_snap_found = ipd->snap_gizmo ?
+ idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) :
+ false;
+ ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) :
+ false;
+ {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ }
+
+ if (is_snap_found) {
+ /* pass */
+ }
+ else {
+ bool use_depth_fallback = true;
+ if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) {
+ /* View plane. */
+ ED_view3d_win_to_3d(
+ ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src);
+ use_depth_fallback = false;
+ }
+ else if (plane_depth == PLACE_DEPTH_SURFACE) {
+ SnapObjectContext *snap_context =
+ (ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(
+ ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) :
+ NULL);
+ if ((snap_context != NULL) &&
+ ED_transform_snap_object_project_view3d(snap_context,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
+ mval_fl,
+ NULL,
+ NULL,
+ ipd->co_src,
+ NULL)) {
+ use_depth_fallback = false;
+ }
+ }
+
+ /* Use as fallback to surface. */
+ if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) {
+ /* Cursor plane. */
+ float plane[4];
+ plane_from_point_normal_v3(
+ plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+ if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) {
+ use_depth_fallback = false;
+ }
+ /* Even if the calculation works, it's possible the point found is behind the view. */
+ if (rv3d->is_persp) {
+ float dir[3];
+ sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src);
+ if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) {
+ use_depth_fallback = true;
+ }
+ }
+ }
+
+ if (use_depth_fallback) {
+ float co_depth[3];
+ /* Fallback to view center. */
+ negate_v3_v3(co_depth, rv3d->ofs);
+ ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src);
+ }
+ }
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]);
+
+ copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
+}
+
+static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
+
+ struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__);
+ op->customdata = ipd;
+
+ ipd->scene = CTX_data_scene(C);
+ ipd->area = CTX_wm_area(C);
+ ipd->region = CTX_wm_region(C);
+ ipd->v3d = CTX_wm_view3d(C);
+
+ if (wait_for_input) {
+ ipd->wait_for_input = true;
+ /* TODO: support snapping when not using with tool. */
+#if 0
+ WM_gizmo_group_type_ensure(view3d_gzgt_placement_id);
+#endif
+ }
+ else {
+ view3d_interactive_add_begin(C, op, event);
+ }
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
+{
+ UNUSED_VARS(C);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
+
+ ED_region_tag_redraw(ipd->region);
+
+ MEM_freeN(ipd);
+}
+
+static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
+{
+ view3d_interactive_add_exit(C, op);
+}
+
+enum {
+ PLACE_MODAL_SNAP_ON,
+ PLACE_MODAL_SNAP_OFF,
+ PLACE_MODAL_FIXED_ASPECT_ON,
+ PLACE_MODAL_FIXED_ASPECT_OFF,
+ PLACE_MODAL_PIVOT_CENTER_ON,
+ PLACE_MODAL_PIVOT_CENTER_OFF,
+};
+
+void viewplace_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items[] = {
+ {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
+ {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
+ {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
+ {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
+ {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
+ {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ const char *keymap_name = "View3D Placement Modal Map";
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
+
+ /* This function is called for each space-type, only needs to add map once. */
+ if (keymap && keymap->modal_items) {
+ return;
+ }
+
+ keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
+
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
+}
+
+static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ UNUSED_VARS(C, op);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ARegion *region = ipd->region;
+ bool do_redraw = false;
+ bool do_cursor_update = false;
+
+ /* Handle modal key-map. */
+ if (event->type == EVT_MODAL_MAP) {
+ bool is_fallthrough = false;
+ switch (event->val) {
+ case PLACE_MODAL_FIXED_ASPECT_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_FIXED_ASPECT_OFF: {
+ ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_OFF: {
+ ipd->step[ipd->step_index].is_centered = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_SNAP_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_SNAP_OFF: {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->is_snap_invert = is_fallthrough;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ do_cursor_update = true;
+ break;
+ }
+ }
+ }
+
+ if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ else if (event->type == MOUSEMOVE) {
+ do_cursor_update = true;
+ }
+
+ if (ipd->wait_for_input) {
+ if (ELEM(event->type, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ view3d_interactive_add_begin(C, op, event);
+ ipd->wait_for_input = false;
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_RELEASE) {
+ /* Set secondary plane. */
+
+ /* Create normal. */
+ {
+ RegionView3D *rv3d = region->regiondata;
+ float no_temp[3];
+ float no[3];
+ cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
+ cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
+ normalize_v3(no);
+
+ plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
+ }
+
+ copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
+ ipd->step_index = STEP_DEPTH;
+
+ /* Keep these values from the previous step. */
+ ipd->step[1].is_centered = ipd->step[0].is_centered;
+ ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect;
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+
+ float location[3];
+ float rotation[3];
+ float scale[3];
+
+ float matrix_orient_axis[3][3];
+ copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
+ if (ipd->orient_axis != 2) {
+ swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
+ swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
+ }
+ /* Needed for shapes where the sign matters (cone for eg). */
+ {
+ float delta[3];
+ sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
+ if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
+ negate_v3(matrix_orient_axis[2]);
+
+ /* Only flip Y so we don't flip a single axis which causes problems. */
+ negate_v3(matrix_orient_axis[1]);
+ }
+ }
+
+ mat3_to_eul(rotation, matrix_orient_axis);
+
+ mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
+ const int cube_verts[3] = {3, 1, 4};
+ for (int i = 0; i < 3; i++) {
+ scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
+ }
+
+ wmOperatorType *ot = NULL;
+ PointerRNA op_props;
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) {
+ ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) {
+ ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
+ }
+
+ if (ot != NULL) {
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ if (ipd->use_tool) {
+ bToolRef *tref = ipd->area->runtime.tool;
+ PointerRNA temp_props;
+ WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
+ SWAP(PointerRNA, temp_props, op_props);
+ WM_operator_properties_free(&temp_props);
+ }
+
+ RNA_float_set_array(&op_props, "rotation", rotation);
+ RNA_float_set_array(&op_props, "location", location);
+ RNA_float_set_array(&op_props, "scale", scale);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ WM_operator_properties_free(&op_props);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (do_cursor_update) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ /* Calculate the snap location on mouse-move or when toggling snap. */
+ bool is_snap_found_prev = ipd->is_snap_found;
+ ipd->is_snap_found = false;
+ if (ipd->use_snap) {
+ if (ipd->snap_gizmo != NULL) {
+ ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap);
+ if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ ipd->region,
+ ipd->v3d,
+ NULL,
+ mval_fl,
+ ipd->snap_co,
+ NULL)) {
+ ipd->is_snap_found = true;
+ }
+ ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo);
+ }
+ }
+
+ /* Workaround because test_select doesn't run at the same time as the modal operator. */
+ if (is_snap_found_prev != ipd->is_snap_found) {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL);
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) {
+ /* pass */
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) {
+ /* pass */
+ }
+ }
+
+ /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
+ float close[3], delta[3];
+ closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst);
+ sub_v3_v3v3(delta, close, ipd->step[0].co_dst);
+ sub_v3_v3(ipd->step[1].co_dst, delta);
+ }
+ do_redraw = true;
+ }
+
+ if (do_redraw) {
+ ED_region_tag_redraw(region);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool view3d_interactive_add_poll(bContext *C)
+{
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH);
+}
+
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Primitive Object";
+ ot->description = "Interactively add an object";
+ ot->idname = "VIEW3D_OT_interactive_add";
+
+ /* api callbacks */
+ ot->invoke = view3d_interactive_add_invoke;
+ ot->modal = view3d_interactive_add_modal;
+ ot->cancel = view3d_interactive_add_cancel;
+ ot->poll = view3d_interactive_add_poll;
+
+ /* Note, let the operator we call handle undo and registering it's self. */
+ /* flags */
+ ot->flag = 0;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ /* Normally not accessed directly, leave unset and check the active tool. */
+ static const EnumPropertyItem primitive_type[] = {
+ {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
+ {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
+ {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Primitive", "");
+ RNA_def_property_enum_items(prop, primitive_type);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region");
+ RNA_def_property_enum_default(prop, 2);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem plane_depth_items[] = {
+ {PLACE_DEPTH_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Start placing on the surface, using the 3D cursor position as a fallback"},
+ {PLACE_DEPTH_CURSOR_PLANE,
+ "CURSOR_PLANE",
+ 0,
+ "3D Cursor Plane",
+ "Start placement using a point projected onto the selected axis at the 3D cursor position"},
+ {PLACE_DEPTH_CURSOR_VIEW,
+ "CURSOR_VIEW",
+ 0,
+ "3D Cursor View",
+ "Start placement using the mouse cursor projected onto the view plane"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor");
+ RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE);
+ RNA_def_property_enum_items(prop, plane_depth_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem origin_items[] = {
+ {PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"},
+ {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
+ RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE);
+ RNA_def_property_enum_items(prop, origin_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* When not accessed via a tool. */
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Placement Gizmo Group
+ *
+ * This is currently only used for snapping before the tool is initialized,
+ * we could show a placement plane here.
+ * \{ */
+
+static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmo *gizmo;
+
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ /* Don't handle any events, this is for display only. */
+ gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
+ }
+}
+
+void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Placement Widget";
+ gzgt->idname = view3d_gzgt_placement_id;
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_placement_setup;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 2ce2edb98fe..8c60e36a141 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -411,6 +411,7 @@ typedef struct LassoSelectUserData {
const int (*mcoords)[2];
int mcoords_len;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
int pass;
@@ -434,6 +435,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->mcoords = mcoords;
r_data->mcoords_len = mcoords_len;
r_data->sel_op = sel_op;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
/* runtime */
r_data->pass = 0;
@@ -903,6 +906,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
LassoSelectUserData *data = userData;
@@ -913,17 +917,17 @@ static void do_lasso_select_curve__doSelect(void *userData,
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
}
bezt->f1 = bezt->f3 = bezt->f2;
data->is_changed = true;
@@ -933,7 +937,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -945,6 +949,7 @@ static bool do_lasso_select_curve(ViewContext *vc,
const int mcoords_len,
const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
LassoSelectUserData data;
rcti rect;
@@ -952,13 +957,23 @@ static bool do_lasso_select_curve(ViewContext *vc,
view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
if (data.is_changed) {
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
}
@@ -2559,6 +2574,7 @@ typedef struct BoxSelectUserData {
const rctf *rect_fl;
rctf _rect_fl;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_done;
@@ -2577,6 +2593,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
r_data->sel_op = sel_op;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
/* runtime */
r_data->is_done = false;
@@ -2707,6 +2725,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
BoxSelectUserData *data = userData;
@@ -2716,17 +2735,17 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
data->is_changed = true;
}
bezt->f1 = bezt->f3 = bezt->f2;
@@ -2736,7 +2755,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -2744,17 +2763,28 @@ static void do_nurbs_box_select__doSelect(void *userData,
}
static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
BoxSelectUserData data;
view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return data.is_changed;
@@ -3393,6 +3423,7 @@ typedef struct CircleSelectUserData {
float mval_fl[2];
float radius;
float radius_squared;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_changed;
@@ -3413,6 +3444,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
r_data->radius = rad;
r_data->radius_squared = rad * rad;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
+
/* runtime */
r_data->is_changed = false;
}
@@ -3650,29 +3684,24 @@ static void nurbscurve_circle_doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool UNUSED(handles_visible),
const float screen_co[2])
{
CircleSelectUserData *data = userData;
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (bp) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag);
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
- bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
+ if (beztindex == 0) {
+ SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag);
+ }
+ else if (beztindex == 1) {
+ SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag);
}
else {
- if (beztindex == 0) {
- bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
- }
- else if (beztindex == 1) {
- bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
- }
- else {
- bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
- }
+ SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag);
}
}
data->is_changed = true;
@@ -3683,18 +3712,30 @@ static bool nurbscurve_circle_select(ViewContext *vc,
const int mval[2],
float rad)
{
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool deselect_all = (sel_op == SEL_OP_SET);
CircleSelectUserData data;
bool changed = false;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = vc->obedit->data;
- changed |= ED_curve_deselect_all(curve->editnurb);
- }
- const bool select = (sel_op != SEL_OP_SUB);
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
+ }
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return changed || data.is_changed;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 09e1dca3152..377e8c58ba3 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -86,6 +86,26 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float
UI_GetThemeColor3fv(TH_BACK, r_color);
}
+bool ED_view3d_has_workbench_in_texture_color(const Scene *scene,
+ const Object *ob,
+ const View3D *v3d)
+{
+ if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ return true;
+ }
+ if (ob->mode == OB_MODE_TEXTURE_PAINT) {
+ return true;
+ }
+ }
+ else if (v3d->shading.type == OB_RENDER) {
+ if (STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH)) {
+ return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR;
+ }
+ }
+ return false;
+}
+
Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
{
/* establish the camera object,
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 8ee52756f27..7aefd173953 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
- ret = ED_transform_snap_object_project_ray(walk->snap_context,
- walk->depsgraph,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- },
- ray_start,
- ray_normal,
- r_distance,
- r_location,
- r_normal_dummy);
+ ret = ED_transform_snap_object_project_ray(
+ walk->snap_context,
+ walk->depsgraph,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ /* Avoid having to convert the edit-mesh to a regular mesh. */
+ .use_object_edit_cage = true,
+ },
+ ray_start,
+ ray_normal,
+ r_distance,
+ r_location,
+ r_normal_dummy);
/* artificially scale the distance to the scene size */
*r_distance /= walk->grid;
@@ -449,7 +452,6 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
walk->rv3d = CTX_wm_region_view3d(C);
@@ -553,7 +555,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, walk->scene, 0, walk->region, walk->v3d);
+ walk->scene, 0, walk->region, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph,
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 8e3ad55bae1..5fc65522fe6 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -825,17 +825,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is
}
}
else if (!edit_2d) {
- if (t->orientation.index == 0 || ELEM(cmode, '\0', axis)) {
+ if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) {
/* Successive presses on existing axis, cycle orientation modes. */
- t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
- initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+ transform_orientations_current_set(t, t->orient_curr);
}
- if (t->orientation.index == 0) {
+ if (t->orient_curr == 0) {
stopConstraint(t);
}
else {
- const short orientation = t->orientation.types[t->orientation.index];
+ const short orientation = t->orient[t->orient_curr].type;
if (is_plane == false) {
setUserConstraint(t, orientation, constraint_axis, msg2);
}
@@ -896,74 +896,59 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_TRANSLATE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
- restoreTransObjects(t);
- resetTransModal(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_SEQ_SLIDE) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else {
- if (t->obedit_type == OB_MESH) {
- if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
- restoreTransObjects(t);
+ if (t->mode == TFM_TRANSLATION) {
+ if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+
+ /* first try edge slide */
+ transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
+ /* if that fails, do vertex slide */
+ if (t->state == TRANS_CANCEL) {
resetTransModal(t);
+ t->state = TRANS_STARTING;
+ transform_mode_init(t, NULL, TFM_VERT_SLIDE);
+ }
+ /* vert slide can fail on unconnected vertices (rare but possible) */
+ if (t->state == TRANS_CANCEL) {
+ resetTransModal(t);
+ t->state = TRANS_STARTING;
+ restoreTransObjects(t);
resetTransRestrictions(t);
-
- /* first try edge slide */
- transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
- /* if that fails, do vertex slide */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- transform_mode_init(t, NULL, TFM_VERT_SLIDE);
- }
- /* vert slide can fail on unconnected vertices (rare but possible) */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- restoreTransObjects(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- }
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
}
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- if (t->mode == TFM_TRANSLATION) {
- restoreTransObjects(t);
+ restoreTransObjects(t);
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
}
+ else if (t->mode == TFM_SEQ_SLIDE) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
break;
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_TRANSLATION,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -982,15 +967,23 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_RESIZE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_TRANSLATION,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (t->mode == TFM_RESIZE) {
+ if (t->options & CTX_MOVIECLIP) {
+ restoreTransObjects(t);
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ }
+ else if (t->mode == TFM_SHRINKFATTEN) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
/* Scale isn't normally very useful after extrude along normals, see T39756 */
- if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) {
+ if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) {
stopConstraint(t);
}
@@ -1002,20 +995,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
handled = true;
}
- else if (t->mode == TFM_SHRINKFATTEN) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_RESIZE) {
- if (t->options & CTX_MOVIECLIP) {
- restoreTransObjects(t);
-
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- }
break;
case TFM_MODAL_SNAP_INV_ON:
@@ -1229,7 +1208,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1244,7 +1223,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
+ if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1260,7 +1239,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1615,6 +1594,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
int proportional = 0;
PropertyRNA *prop;
+ if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) &&
+ ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) {
+ /* When redoing these modes the first time, it's more convenient to save
+ * the Global orientation. */
+ mul_m3_v3(t->spacemtx, t->values_final);
+ unit_m3(t->spacemtx);
+
+ BLI_assert(t->orient_curr == 0);
+ t->orient[0].type = V3D_ORIENT_GLOBAL;
+ }
+
// Save back mode in case we're in the generic operator
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
RNA_property_enum_set(op->ptr, prop, t->mode);
@@ -1723,19 +1713,20 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
- short orient_set, orient_cur;
- orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1;
- orient_cur = t->orientation.types[t->orientation.index];
+ short orient_type_set, orient_type_curr;
+ orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) :
+ -1;
+ orient_type_curr = t->orient[t->orient_curr].type;
- if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) {
- RNA_property_enum_set(op->ptr, prop, orient_cur);
- orient_set = orient_cur;
+ if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+ RNA_property_enum_set(op->ptr, prop, orient_type_curr);
+ orient_type_set = orient_type_curr;
}
if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
!RNA_property_is_set(op->ptr, prop))) {
/* Set the first time to register on redo. */
- RNA_property_enum_set(op->ptr, prop, orient_set);
+ RNA_property_enum_set(op->ptr, prop, orient_type_set);
RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
}
}
@@ -1883,11 +1874,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initTransInfo(C, t, op, event);
/* Use the custom orientation when it is set. */
- short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ?
- V3D_ORIENT_CUSTOM_MATRIX :
- t->orientation.types[t->orientation.index];
-
- initTransformOrientation(C, t, orientation);
+ short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr;
+ transform_orientations_current_set(t, orient_index);
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_apply = ED_region_draw_cb_activate(
@@ -2043,7 +2031,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* Constraint init from operator */
if (t->con.mode & CON_APPLY) {
- setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s");
+ setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s");
}
/* Don't write into the values when non-modal because they are already set from operator redo
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 503e7bd4691..7720660e2e8 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -113,13 +113,8 @@ typedef struct TransSnap {
} TransSnap;
typedef struct TransCon {
- short orientation;
/** Description of the constraint for header_print. */
char text[50];
- /** Matrix of the constraint space. */
- float mtx[3][3];
- /** Inverse matrix of the constraint space. */
- float imtx[3][3];
/** Projection constraint matrix (same as #imtx with some axis == 0). */
float pmtx[3][3];
/** Initial mouse value for visual calculation
@@ -139,8 +134,7 @@ typedef struct TransCon {
struct TransDataContainer *tc,
struct TransData *td,
const float in[3],
- float out[3],
- float pvec[3]);
+ float out[3]);
/** Apply function pointer for size transformation. */
void (*applySize)(struct TransInfo *t,
struct TransDataContainer *tc,
@@ -520,6 +514,7 @@ typedef struct TransInfo {
/** orientation matrix of the current space. */
float spacemtx[3][3];
+ float spacemtx_inv[3][3];
/** name of the current space, MAX_NAME. */
char spacename[64];
@@ -531,13 +526,11 @@ typedef struct TransInfo {
bool is_launch_event_tweak;
struct {
- short index;
- short types[3];
- /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */
- struct TransformOrientation *custom;
- /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */
- float custom_matrix[3][3];
- } orientation;
+ short type;
+ float matrix[3][3];
+ } orient[3];
+ short orient_curr;
+
/** backup from view3d, to restore on end. */
short gizmo_flag;
@@ -911,8 +904,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]);
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
/*********************** Transform Orientations ******************************/
-
-void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation);
+short transform_orientation_matrix_get(struct bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3]);
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index b07eb6edf5a..0a6e0d6b7f5 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "ED_view3d.h"
@@ -57,6 +58,27 @@
static void drawObjectConstraint(TransInfo *t);
+static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3])
+{
+ unit_m3(r_pmtx);
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ zero_v3(r_pmtx[0]);
+ }
+
+ if (!(t->con.mode & CON_AXIS1)) {
+ zero_v3(r_pmtx[1]);
+ }
+
+ if (!(t->con.mode & CON_AXIS2)) {
+ zero_v3(r_pmtx[2]);
+ }
+
+ float mat[3][3];
+ mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv);
+ mul_m3_m3m3(r_pmtx, t->spacemtx, mat);
+}
+
/* ************************** CONSTRAINTS ************************* */
static void constraintValuesFinal(TransInfo *t, float vec[3])
{
@@ -121,11 +143,9 @@ void constraintNumInput(TransInfo *t, float vec[3])
}
}
-static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
+static void postConstraintChecks(TransInfo *t, float vec[3])
{
- int i = 0;
-
- mul_m3_v3(t->con.imtx, vec);
+ mul_m3_v3(t->spacemtx_inv, vec);
snapGridIncrement(t, vec);
@@ -155,17 +175,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
/* inverse transformation at the end */
}
- if (t->con.mode & CON_AXIS0) {
- pvec[i++] = vec[0];
- }
- if (t->con.mode & CON_AXIS1) {
- pvec[i++] = vec[1];
- }
- if (t->con.mode & CON_AXIS2) {
- pvec[i++] = vec[2];
- }
-
- mul_m3_v3(t->con.mtx, vec);
+ mul_m3_v3(t->spacemtx, vec);
}
static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
@@ -298,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t)
int n = 0;
for (int i = 0; i < 3; i++) {
if (t->con.mode & (CON_AXIS0 << i)) {
- constraint_vector[n++] = t->con.mtx[i];
+ constraint_vector[n++] = t->spacemtx[i];
if (n == 2) {
break;
}
@@ -346,12 +356,8 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
* (in perspective mode, the view vector is relative to the position on screen)
*/
-static void applyAxisConstraintVec(TransInfo *t,
- TransDataContainer *UNUSED(tc),
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyAxisConstraintVec(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3])
{
copy_v3_v3(out, in);
if (!td && t->con.mode & CON_APPLY) {
@@ -371,25 +377,25 @@ static void applyAxisConstraintVec(TransInfo *t,
float c[3];
if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
+ copy_v3_v3(c, t->spacemtx[0]);
}
else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
+ copy_v3_v3(c, t->spacemtx[1]);
}
else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
+ copy_v3_v3(c, t->spacemtx[2]);
}
axisProjection(t, c, in, out);
}
}
- postConstraintChecks(t, out, pvec);
+ postConstraintChecks(t, out);
}
}
/*
* Generic callback for object based spatial constraints applied to linear motion
*
- * At first, the following is applied to the first data in the array
+ * At first, the following is applied without orientation
* The IN vector in projected into the constrained space and then further
* projected along the view vector.
* (in perspective mode, the view vector is relative to the position on screen)
@@ -397,61 +403,19 @@ static void applyAxisConstraintVec(TransInfo *t,
* Further down, that vector is mapped to each data's space.
*/
-static void applyObjectConstraintVec(TransInfo *t,
- TransDataContainer *tc,
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyObjectConstraintVec(
+ TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3])
{
- copy_v3_v3(out, in);
- if (t->con.mode & CON_APPLY) {
- if (!td) {
- mul_m3_v3(t->con.pmtx, out);
-
- const int dims = getConstraintSpaceDimension(t);
- if (dims == 2) {
- if (!is_zero_v3(out)) {
- if (!isPlaneProjectionViewAligned(t)) {
- planeProjection(t, in, out);
- }
- }
- }
- else if (dims == 1) {
- float c[3];
-
- if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
- }
- else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
- }
- else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
- }
- axisProjection(t, c, in, out);
- }
- postConstraintChecks(t, out, pvec);
- copy_v3_v3(out, pvec);
- }
- else {
- int i = 0;
-
- out[0] = out[1] = out[2] = 0.0f;
- if (t->con.mode & CON_AXIS0) {
- out[0] = in[i++];
- }
- if (t->con.mode & CON_AXIS1) {
- out[1] = in[i++];
- }
- if (t->con.mode & CON_AXIS2) {
- out[2] = in[i++];
- }
-
- mul_m3_v3(td->axismtx, out);
- if (t->flag & T_EDIT) {
- mul_m3_v3(tc->mat3_unit, out);
- }
+ if (!td) {
+ applyAxisConstraintVec(t, tc, td, in, out);
+ }
+ else {
+ /* Specific TransData's space. */
+ copy_v3_v3(out, in);
+ mul_m3_v3(t->spacemtx_inv, out);
+ mul_m3_v3(td->axismtx, out);
+ if (t->flag & T_EDIT) {
+ mul_m3_v3(tc->mat3_unit, out);
}
}
}
@@ -478,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t,
smat[2][2] = 1.0f;
}
- mul_m3_m3m3(tmat, smat, t->con.imtx);
- mul_m3_m3m3(smat, t->con.mtx, tmat);
+ mul_m3_m3m3(tmat, smat, t->spacemtx_inv);
+ mul_m3_m3m3(smat, t->spacemtx, tmat);
}
}
@@ -539,15 +503,15 @@ static void applyAxisConstraintRot(
switch (mode) {
case CON_AXIS0:
case (CON_AXIS1 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[0]);
+ copy_v3_v3(vec, t->spacemtx[0]);
break;
case CON_AXIS1:
case (CON_AXIS0 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[1]);
+ copy_v3_v3(vec, t->spacemtx[1]);
break;
case CON_AXIS2:
case (CON_AXIS0 | CON_AXIS1):
- copy_v3_v3(vec, t->con.mtx[2]);
+ copy_v3_v3(vec, t->spacemtx[2]);
break;
}
/* don't flip axis if asked to or if num input */
@@ -620,12 +584,11 @@ static void applyObjectConstraintRot(
/*--------------------- INTERNAL SETUP CALLS ------------------*/
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
+void setConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, space);
t->con.mode = mode;
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
startConstraint(t);
@@ -639,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
- TransDataContainer *tc = t->data_container;
- if (t->data_len_all == 1) {
- float axismtx[3][3];
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx);
- }
- else {
- copy_m3_m3(axismtx, tc->data->axismtx);
- }
-
- setConstraint(t, axismtx, mode, text);
- }
- else {
- BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, tc->data->axismtx);
- t->con.mode = mode;
- getConstraintMatrix(t);
+ BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
+ t->con.mode = mode;
+ projection_matrix_calc(t, t->con.pmtx);
- startConstraint(t);
+ startConstraint(t);
- t->con.drawExtra = drawObjectConstraint;
- t->con.applyVec = applyObjectConstraintVec;
- t->con.applySize = applyObjectConstraintSize;
- t->con.applyRot = applyObjectConstraintRot;
- t->redraw = TREDRAW_HARD;
- }
+ t->con.drawExtra = drawObjectConstraint;
+ t->con.applyVec = applyObjectConstraintVec;
+ t->con.applySize = applyObjectConstraintSize;
+ t->con.applyRot = applyObjectConstraintRot;
+ t->redraw = TREDRAW_HARD;
}
void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
- /* edit-mode now allows local transforms too */
if (t->flag & T_EDIT) {
- /* Use the active (first) edit object. */
- TransDataContainer *tc = t->data_container;
- setConstraint(t, tc->mat3_unit, mode, text);
+ /* Although in edit-mode each object has its local space, use the
+ * orientation of the active object. */
+ setConstraint(t, mode, text);
}
else {
setAxisMatrixConstraint(t, mode, text);
@@ -689,64 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
{
char text[256];
+ const char *spacename = transform_orientations_spacename_get(t, orientation);
+ BLI_snprintf(text, sizeof(text), ftext, spacename);
switch (orientation) {
- case V3D_ORIENT_GLOBAL: {
- float mtx[3][3];
- BLI_snprintf(text, sizeof(text), ftext, TIP_("global"));
- unit_m3(mtx);
- setConstraint(t, mtx, mode, text);
- break;
- }
case V3D_ORIENT_LOCAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("local"));
setLocalConstraint(t, mode, text);
break;
case V3D_ORIENT_NORMAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("normal"));
if (checkUseAxisMatrix(t)) {
setAxisMatrixConstraint(t, mode, text);
+ break;
}
- else {
- setConstraint(t, t->spacemtx, mode, text);
- }
- break;
+ ATTR_FALLTHROUGH;
+ case V3D_ORIENT_GLOBAL:
case V3D_ORIENT_VIEW:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
- float mtx[3][3];
- copy_m3_m3(mtx, t->spacemtx);
- negate_v3(mtx[2]);
- setConstraint(t, mtx, mode, text);
- break;
case V3D_ORIENT_CURSOR:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_GIMBAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CUSTOM_MATRIX:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CUSTOM:
default: {
- BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- char orientation_str[128];
- BLI_snprintf(orientation_str,
- sizeof(orientation_str),
- "%s \"%s\"",
- TIP_("custom orientation"),
- t->orientation.custom->name);
- BLI_snprintf(text, sizeof(text), ftext, orientation_str);
- setConstraint(t, t->spacemtx, mode, text);
+ setConstraint(t, mode, text);
break;
}
}
-
- t->con.orientation = orientation;
-
t->con.mode |= CON_USER;
}
@@ -777,9 +690,9 @@ void drawConstraint(TransInfo *t)
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
add_v3_v3(vec, t->center_global);
- drawLine(t, t->center_global, tc->mtx[0], 'X', 0);
- drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
- drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', 0);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0);
depth_test_enabled = GPU_depth_test_enabled();
if (depth_test_enabled) {
@@ -813,13 +726,13 @@ void drawConstraint(TransInfo *t)
}
if (tc->mode & CON_AXIS0) {
- drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT);
}
if (tc->mode & CON_AXIS1) {
- drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT);
}
if (tc->mode & CON_AXIS2) {
- drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT);
}
}
}
@@ -965,28 +878,6 @@ void stopConstraint(TransInfo *t)
t->num.idx_max = t->idx_max;
}
-void getConstraintMatrix(TransInfo *t)
-{
- float mat[3][3];
- invert_m3_m3(t->con.imtx, t->con.mtx);
- unit_m3(t->con.pmtx);
-
- if (!(t->con.mode & CON_AXIS0)) {
- zero_v3(t->con.pmtx[0]);
- }
-
- if (!(t->con.mode & CON_AXIS1)) {
- zero_v3(t->con.pmtx[1]);
- }
-
- if (!(t->con.mode & CON_AXIS2)) {
- zero_v3(t->con.pmtx[2]);
- }
-
- mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
- mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat);
-}
-
/*------------------------- MMB Select -------------------------------*/
void initSelectConstraint(TransInfo *t, bool force_global)
@@ -996,11 +887,11 @@ void initSelectConstraint(TransInfo *t, bool force_global)
orientation = V3D_ORIENT_GLOBAL;
}
else {
- if (t->orientation.index == 0) {
- t->orientation.index = 1;
- initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ if (t->orient_curr == 0) {
+ t->orient_curr = 1;
+ transform_orientations_current_set(t, t->orient_curr);
}
- orientation = t->orientation.types[t->orientation.index];
+ orientation = t->orient[t->orient_curr].type;
}
setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "");
@@ -1070,7 +961,7 @@ static void setNearestAxis3d(TransInfo *t)
for (i = 0; i < 3; i++) {
float axis[3], axis_2d[2];
- copy_v3_v3(axis, t->con.mtx[i]);
+ copy_v3_v3(axis, t->spacemtx[i]);
mul_v3_fl(axis, zfac);
/* now we can project to get window coordinate */
@@ -1139,7 +1030,7 @@ void setNearestAxis(TransInfo *t)
setNearestAxis2d(t);
}
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
}
/*-------------- HELPER FUNCTIONS ----------------*/
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index c98234c83da..b57a7599321 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -27,7 +27,7 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setConstraint(TransInfo *t, int mode, const char text[]);
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
@@ -35,7 +35,6 @@ void drawConstraint(TransInfo *t);
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
-void getConstraintMatrix(TransInfo *t);
void initSelectConstraint(TransInfo *t, bool force_global);
void selectConstraint(TransInfo *t);
void postSelectConstraint(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index d6875f173e3..b91542a80fc 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1848,7 +1848,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
if (IS_AUTOKEY_ON(t->scene)) {
Scene *scene = t->scene;
- ED_mask_layer_shape_auto_key_select(mask, CFRA);
+ if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
+ DEG_id_tag_update(&mask->id, 0);
+ }
}
}
@@ -1869,6 +1872,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
+ ntreeUpdateTree(bmain, ntree);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 42ffe675dc5..1f113a36a89 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -93,9 +93,8 @@ void createTransCurveVerts(TransInfo *t)
int count = 0, countsel = 0;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
/* count total of vertices, check identical as in 2nd loop for making transdata! */
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
@@ -163,9 +162,8 @@ void createTransCurveVerts(TransInfo *t)
int a;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
transform_mode_use_local_origins(t));
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 24dda8c8464..07b2f07bf2c 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1450,7 +1450,6 @@ static void UVsToTransData(const float aspect[2],
void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1500,7 +1499,7 @@ void createTransUVs(bContext *C, TransInfo *t)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
- if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
continue;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 4472facf183..b1e69dde0ac 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1626,7 +1626,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) {
- /* For operators whose `t->values` is array, set contrain so that the
+ /* For operators whose `t->values` is array, set constraint so that the
* orientation is more intuitive in the Redo Panel. */
for (int i = 3; i--;) {
constraint_axis[i] |= t->values[i] != 0.0f;
@@ -1650,25 +1650,21 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
{
TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- TransformOrientation *custom_orientation = NULL;
short orient_type_set = -1;
short orient_type_matrix_set = -1;
short orient_type_scene = orient_slot->type;
if (orient_type_scene == V3D_ORIENT_CUSTOM) {
const int index_custom = orient_slot->index_custom;
- custom_orientation = BKE_scene_transform_orientation_find(t->scene, index_custom);
orient_type_scene += index_custom;
}
- short orient_type_default = V3D_ORIENT_GLOBAL;
- short orient_type_constraint[2];
+ short orient_types[3];
+ float custom_matrix[3][3];
+ bool use_orient_axis = false;
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
t->orient_axis = RNA_property_enum_get(op->ptr, prop);
-
- /* For transfor modes that require "orient_axis" use
- * `V3D_ORIENT_VIEW` as default. */
- orient_type_default = V3D_ORIENT_VIEW;
+ use_orient_axis = true;
}
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
@@ -1681,26 +1677,28 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
orient_type_set = V3D_ORIENT_GLOBAL;
}
- else {
- custom_orientation = BKE_scene_transform_orientation_find(
- t->scene, orient_type_default - V3D_ORIENT_CUSTOM);
- }
}
/* Change the default orientation to be used when redoing. */
- orient_type_default = orient_type_set;
- orient_type_constraint[0] = orient_type_set;
- orient_type_constraint[1] = orient_type_scene;
+ orient_types[0] = orient_type_set;
+ orient_types[1] = orient_type_set;
+ orient_types[2] = orient_type_scene;
}
else {
- orient_type_constraint[0] = orient_type_scene;
- orient_type_constraint[1] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
- V3D_ORIENT_LOCAL;
+ if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) {
+ orient_types[0] = V3D_ORIENT_VIEW;
+ }
+ else {
+ orient_types[0] = orient_type_scene;
+ }
+ orient_types[1] = orient_type_scene;
+ orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+ V3D_ORIENT_LOCAL;
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
RNA_property_is_set(op->ptr, prop))) {
- RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]);
+ RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
RNA_property_is_set(op->ptr, prop)) {
@@ -1715,18 +1713,30 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (orient_type_matrix_set == orient_type_set) {
/* Constraints are forced to use the custom matrix when redoing. */
- orient_type_default = V3D_ORIENT_CUSTOM_MATRIX;
+ orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX;
}
}
- t->orientation.types[0] = orient_type_default;
- t->orientation.types[1] = orient_type_constraint[0];
- t->orientation.types[2] = orient_type_constraint[1];
- t->orientation.custom = custom_orientation;
-
if (t->con.mode & CON_APPLY) {
- t->orientation.index = 1;
+ t->orient_curr = 1;
}
+
+ /* For efficiency, avoid calculating the same orientation twice. */
+ for (int i = 1; i < 3; i++) {
+ t->orient[i].type = transform_orientation_matrix_get(
+ C, t, orient_types[i], custom_matrix, t->orient[i].matrix);
+ }
+
+ if (orient_types[0] != orient_types[1]) {
+ t->orient[0].type = transform_orientation_matrix_get(
+ C, t, orient_types[0], custom_matrix, t->orient[0].matrix);
+ }
+ else {
+ memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0]));
+ }
+
+ const char *spacename = transform_orientations_spacename_get(t, orient_types[0]);
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 50317d8b395..c63e90ac2b7 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -217,14 +217,12 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
ScrArea *area = CTX_wm_area(C);
bool changed = false;
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = ED_space_image(sima);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, NULL, &objects_len);
- if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) {
+ if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
changed = true;
}
MEM_freeN(objects);
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index b575030778f..04be7048791 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -929,7 +929,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
* if handles are hidden then only check the center points.
* If the center knot is selected then only use this as the center point.
*/
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) {
if (bezt->f2 & SELECT) {
calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local);
totsel++;
@@ -1390,21 +1390,21 @@ void drawDial3d(const TransInfo *t)
if (tc->mode & CON_APPLY) {
if (tc->mode & CON_AXIS0) {
axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], tc->mtx[0]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[0]);
}
else if (tc->mode & CON_AXIS1) {
axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], tc->mtx[1]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[1]);
}
else {
BLI_assert((tc->mode & CON_AXIS2) != 0);
axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], tc->mtx[2]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[2]);
}
}
else {
axis_idx = MAN_AXIS_ROT_C;
- negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
+ copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
scale *= 1.2f;
line_with -= 1.0f;
}
@@ -2201,6 +2201,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if (ob && ob->mode & OB_MODE_EDIT) {
+ copy_m4_m4(gz->matrix_space, ob->obmat);
+ }
+ else {
+ unit_m4(gz->matrix_space);
+ }
+
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
@@ -2258,15 +2267,6 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
- wmGizmo *gz = xgzgroup->gizmo;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- if (ob && ob->mode & OB_MODE_EDIT) {
- copy_m4_m4(gz->matrix_space, ob->obmat);
- }
- else {
- unit_m4(gz->matrix_space);
- }
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 4c14c3aebd7..c2c880b03ff 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
}
+/* Informs if the mode can be switched during modal. */
+bool transform_mode_is_changeable(const int mode)
+{
+ return ELEM(mode,
+ TFM_ROTATION,
+ TFM_RESIZE,
+ TFM_TRACKBALL,
+ TFM_TRANSLATION,
+ TFM_EDGE_SLIDE,
+ TFM_VERT_SLIDE);
+}
+
/* -------------------------------------------------------------------- */
/** \name Transform Locks
* \{ */
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6180f6d3477..074e89390c2 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
bool transdata_check_local_center(TransInfo *t, short around);
+bool transform_mode_is_changeable(const int mode);
void protectedTransBits(short protectflag, float vec[3]);
void constraintTransLim(TransInfo *t, TransData *td);
void postInputRotation(TransInfo *t, float values[3]);
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 ee91459dcdd..8690cd54a3b 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -101,9 +101,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
snapSequenceBounds(t, mval);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
- t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, tvec);
copy_v3_v3(t->values_final, tvec);
}
else {
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index f52bfda0d14..55c97630487 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -146,7 +146,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
float axis_final[3];
- copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+ /* Use the negative axis to match the default Z axis of the view matrix. */
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index da34bf50ba3..3eeb8a1e758 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -56,14 +56,14 @@ static void initShear_mouseInputMode(TransInfo *t)
copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
/* Needed for axis aligned view gizmo. */
- if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) {
+ if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) {
if (t->orient_axis_ortho == 0) {
- if (t->center2d[1] < t->mouse.imval[1]) {
+ if (t->center2d[1] > t->mouse.imval[1]) {
dir_flip = !dir_flip;
}
}
else if (t->orient_axis_ortho == 1) {
- if (t->center2d[0] < t->mouse.imval[0]) {
+ if (t->center2d[0] > t->mouse.imval[0]) {
dir_flip = !dir_flip;
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 0a7d8bd90d3..69552eda5bf 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -277,8 +277,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
}
if (t->con.applyVec) {
- float pvec[3];
- t->con.applyVec(t, tc, td, vec, tvec, pvec);
+ t->con.applyVec(t, tc, td, vec, tvec);
}
else {
copy_v3_v3(tvec, vec);
@@ -319,45 +318,39 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
- float values_final[3];
+ float global_dir[3];
if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
+ mul_v3_m3v3(global_dir, t->spacemtx, t->values);
}
else {
- copy_v3_v3(t->values_final, t->values);
+ copy_v3_v3(global_dir, t->values);
if ((t->con.mode & CON_APPLY) == 0) {
- snapGridIncrement(t, t->values_final);
+ snapGridIncrement(t, global_dir);
}
- if (applyNumInput(&t->num, t->values_final)) {
- removeAspectRatio(t, t->values_final);
+ if (applyNumInput(&t->num, global_dir)) {
+ removeAspectRatio(t, global_dir);
}
- applySnapping(t, t->values_final);
+ applySnapping(t, global_dir);
}
- copy_v3_v3(values_final, t->values_final);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
- headerTranslation(t, pvec, str);
-
- /* only so we have re-usable value with redo, see T46741. */
- mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
+ float in[3];
+ copy_v3_v3(in, global_dir);
+ t->con.applyVec(t, NULL, NULL, in, global_dir);
+ headerTranslation(t, global_dir, str);
}
else {
- headerTranslation(t, t->values_final, str);
- copy_v3_v3(values_final, t->values_final);
+ headerTranslation(t, global_dir, str);
}
- /* don't use 't->values' now on */
-
- applyTranslationValue(t, values_final);
+ applyTranslationValue(t, global_dir);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
- applyTranslationValue(t, values_final);
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+ applyTranslationValue(t, global_dir);
/* In proportional edit it can happen that */
/* vertices in the radius of the brush end */
@@ -368,8 +361,10 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
}
- recalcData(t);
+ /* Set the redo value. */
+ mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir);
+ recalcData(t);
ED_area_status_text(t->area, str);
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 81c63278366..32269e1bacc 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -438,79 +438,148 @@ static int armature_bone_transflags_update_recursive(bArmature *arm,
return total;
}
-void initTransformOrientation(bContext *C, TransInfo *t, short orientation)
+/* Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one
+ * informed is returned */
+short transform_orientation_matrix_get(bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3])
{
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_active_object(C);
switch (orientation) {
case V3D_ORIENT_GLOBAL:
- unit_m3(t->spacemtx);
- BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
- break;
+ unit_m3(r_spacemtx);
+ return V3D_ORIENT_GLOBAL;
case V3D_ORIENT_GIMBAL:
- unit_m3(t->spacemtx);
- if (ob && gimbal_axis(ob, t->spacemtx)) {
- BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename));
- break;
+ unit_m3(r_spacemtx);
+ if (ob && gimbal_axis(ob, r_spacemtx)) {
+ return V3D_ORIENT_GIMBAL;
}
ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
+
case V3D_ORIENT_NORMAL:
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
- BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename));
- ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
- break;
+ ED_getTransformOrientationMatrix(C, r_spacemtx, t->around);
+ return V3D_ORIENT_NORMAL;
}
ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
- case V3D_ORIENT_LOCAL:
- BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename));
+ case V3D_ORIENT_LOCAL:
if (ob) {
- copy_m3_m4(t->spacemtx, ob->obmat);
- normalize_m3(t->spacemtx);
+ copy_m3_m4(r_spacemtx, ob->obmat);
+ normalize_m3(r_spacemtx);
+ return V3D_ORIENT_LOCAL;
}
- else {
- unit_m3(t->spacemtx);
- }
-
- break;
+ unit_m3(r_spacemtx);
+ return V3D_ORIENT_GLOBAL;
case V3D_ORIENT_VIEW: {
float mat[3][3];
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
- BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
- copy_m3_m4(mat, t->viewinv);
+ RegionView3D *rv3d = t->region->regiondata;
+ copy_m3_m4(mat, rv3d->viewinv);
normalize_m3(mat);
}
else {
unit_m3(mat);
}
- negate_v3(mat[2]);
- copy_m3_m3(t->spacemtx, mat);
- break;
- }
- case V3D_ORIENT_CURSOR: {
- BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
- BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
- break;
+ copy_m3_m3(r_spacemtx, mat);
+ return V3D_ORIENT_VIEW;
}
+ case V3D_ORIENT_CURSOR:
+ BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, r_spacemtx);
+ return V3D_ORIENT_CURSOR;
+
case V3D_ORIENT_CUSTOM_MATRIX:
- BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
- copy_m3_m3(t->spacemtx, t->orientation.custom_matrix);
- break;
+ copy_m3_m3(r_spacemtx, custom);
+ return V3D_ORIENT_CUSTOM_MATRIX;
+
case V3D_ORIENT_CUSTOM:
default:
BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
- if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
+ TransformOrientation *ts = BKE_scene_transform_orientation_find(
+ t->scene, orientation - V3D_ORIENT_CUSTOM);
+ if (applyTransformOrientation(ts, r_spacemtx, t->spacename)) {
/* pass */
}
else {
- unit_m3(t->spacemtx);
+ unit_m3(r_spacemtx);
}
break;
}
+
+ return orientation;
+}
+
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type)
+{
+ switch (orient_type) {
+ case V3D_ORIENT_GLOBAL:
+ return TIP_("global");
+ case V3D_ORIENT_GIMBAL:
+ return TIP_("gimbal");
+ case V3D_ORIENT_NORMAL:
+ return TIP_("normal");
+ case V3D_ORIENT_LOCAL:
+ return TIP_("local");
+ case V3D_ORIENT_VIEW:
+ return TIP_("view");
+ case V3D_ORIENT_CURSOR:
+ return TIP_("cursor");
+ case V3D_ORIENT_CUSTOM_MATRIX:
+ return TIP_("custom");
+ case V3D_ORIENT_CUSTOM:
+ default:
+ BLI_assert(orient_type >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *ts = BKE_scene_transform_orientation_find(
+ t->scene, orient_type - V3D_ORIENT_CUSTOM);
+ return ts->name;
+ }
+}
+
+void transform_orientations_current_set(TransInfo *t, const short orient_index)
+{
+ const short orientation = t->orient[orient_index].type;
+ const char *spacename;
+ switch (orientation) {
+ case V3D_ORIENT_GLOBAL:
+ spacename = TIP_("global");
+ break;
+ case V3D_ORIENT_GIMBAL:
+ spacename = TIP_("gimbal");
+ break;
+ case V3D_ORIENT_NORMAL:
+ spacename = TIP_("normal");
+ break;
+ case V3D_ORIENT_LOCAL:
+ spacename = TIP_("local");
+ break;
+ case V3D_ORIENT_VIEW:
+ spacename = TIP_("view");
+ break;
+ case V3D_ORIENT_CURSOR:
+ spacename = TIP_("cursor");
+ break;
+ case V3D_ORIENT_CUSTOM_MATRIX:
+ spacename = TIP_("custom");
+ break;
+ case V3D_ORIENT_CUSTOM:
+ default:
+ BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *ts = BKE_scene_transform_orientation_find(
+ t->scene, orientation - V3D_ORIENT_CUSTOM);
+ spacename = ts->name;
+ break;
+ }
+
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
+ copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix);
+ invert_m3_m3(t->spacemtx_inv, t->spacemtx);
}
/**
@@ -852,7 +921,7 @@ int getTransformOrientation_ex(const bContext *C,
}
}
else {
- const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ const bool use_handle = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index cb4446deb99..50f525a324b 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -56,6 +56,7 @@
#include "WM_types.h"
+#include "ED_gizmo_library.h"
#include "ED_image.h"
#include "ED_markers.h"
#include "ED_node.h"
@@ -178,99 +179,53 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
(t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
- TransSnapPoint *p;
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float imat[4][4];
- float size;
+ const float *loc_cur = NULL;
+ const float *loc_prev = NULL;
+ const float *normal = NULL;
GPU_depth_test(false);
- size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (!BLI_listbase_is_empty(&t->tsnap.points)) {
+ /* Draw snap points. */
- invert_m4_m4(imat, rv3d->viewmat);
+ float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- for (p = t->tsnap.points.first; p; p = p->next) {
- if (p == t->tsnap.selectedPoint) {
- immUniformColor4ubv(selectedCol);
- }
- else {
- immUniformColor4ubv(col);
+ LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
+ if (p == t->tsnap.selectedPoint) {
+ immUniformColor4ubv(selectedCol);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
+ imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
- imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos);
- }
-
- if (t->tsnap.status & POINT_INIT) {
- immUniformColor4ubv(activeCol);
-
- imm_drawcircball(
- t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos);
+ immUnbindProgram();
}
/* draw normal if needed */
if (usingSnappingNormal(t) && validSnappingNormal(t)) {
- immUniformColor4ubv(activeCol);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
- immVertex3f(pos,
- t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
- t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
- t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
- immEnd();
+ normal = t->tsnap.snapNormal;
}
if (draw_target) {
- /* Draw snapTarget */
- float targ_co[3], vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
- copy_v3_v3(targ_co, t->tsnap.snapTarget);
- float px_size = 0.75f * size * ED_view3d_pixel_size(rv3d, targ_co);
-
- mul_v3_v3fl(vx, imat[0], px_size);
- mul_v3_v3fl(vy, imat[1], px_size);
-
- add_v3_v3v3(v1, vx, vy);
- sub_v3_v3v3(v2, vx, vy);
- negate_v3_v3(v3, v1);
- negate_v3_v3(v4, v2);
-
- add_v3_v3(v1, targ_co);
- add_v3_v3(v2, targ_co);
- add_v3_v3(v3, targ_co);
- add_v3_v3(v4, targ_co);
-
- immUniformColor4ubv(col);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex3fv(pos, v3);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v4);
- immVertex3fv(pos, v2);
- immEnd();
-
- if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) {
- immUnbindProgram();
-
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1f("dash_width", 6.0f * U.pixelsize);
- immUniform1f("dash_factor", 1.0f / 4.0f);
- immUniformColor4ubv(col);
+ loc_prev = t->tsnap.snapTarget;
+ }
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, targ_co);
- immVertex3fv(pos, t->tsnap.snapPoint);
- immEnd();
- }
+ if (validSnap(t)) {
+ loc_cur = t->tsnap.snapPoint;
}
- immUnbindProgram();
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
GPU_depth_test(true);
}
@@ -590,7 +545,6 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
static void initSnappingMode(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
ToolSettings *ts = t->settings;
/* All obedit types will match. */
const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
@@ -687,7 +641,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- bmain, t->scene, 0, t->region, t->view);
+ t->scene, 0, t->region, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -1106,7 +1060,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- Image *ima = ED_space_image(t->area->spacedata.first);
float co[2];
UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
@@ -1117,7 +1070,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_sq = FLT_MAX;
if (ED_uvedit_nearest_uv_multi(
- t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
@@ -1750,8 +1703,8 @@ static void applyGridIncrement(
float local_axis[3];
float pos_on_axis[3];
- copy_v3_v3(local_axis, t->con.mtx[i]);
- copy_v3_v3(pos_on_axis, t->con.mtx[i]);
+ copy_v3_v3(local_axis, t->spacemtx[i]);
+ copy_v3_v3(pos_on_axis, t->spacemtx[i]);
/* amount of movement on axis from initial pos */
mul_v3_fl(pos_on_axis, val[i]);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 2cfeedbb346..77bb0c1c785 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -110,7 +110,6 @@ typedef struct SnapObjectData {
} SnapObjectData;
struct SnapObjectContext {
- Main *bmain;
Scene *scene;
int flag;
@@ -1707,8 +1706,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
&nearest.dist_sq,
nearest.co)) {
nearest.index = vindex[v_id];
- nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata);
elem = SCE_SNAP_MODE_VERTEX;
+ if (r_no) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+ nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata);
+ mul_transposed_mat3_m4_v3(imat, r_no);
+ normalize_v3(r_no);
+ }
}
}
}
@@ -1726,10 +1731,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
vmid,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_MIDPOINT;
}
@@ -1757,11 +1758,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
v_near,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
-
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
}
@@ -1778,15 +1774,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
mul_m4_v3(obmat, r_loc);
}
- if (r_no) {
- float imat[4][4];
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(r_no, nearest.no);
- mul_transposed_mat3_m4_v3(imat, r_no);
- normalize_v3(r_no);
- }
-
*r_index = nearest.index;
}
@@ -2863,13 +2850,12 @@ static short snapObjectsRay(SnapObjectContext *sctx,
/** \name Public Object Snapping API
* \{ */
-SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag)
+SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
sctx->flag = flag;
- sctx->bmain = bmain;
sctx->scene = scene;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
@@ -2880,14 +2866,13 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *s
return sctx;
}
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain,
- Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene,
int flag,
/* extra args for view3d */
const ARegion *region,
const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag);
sctx->use_v3d = true;
sctx->v3d_data.region = region;
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index f22e18de7a1..2df26abe8b3 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -216,7 +216,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) {
BKE_library_foreach_ID_link(
- bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY);
+ bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY);
}
/* Tag depsgraph to update data-block for changes that happened between the
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index c072220842e..edfbfd0cdc3 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -58,8 +58,7 @@
/* UV Utilities */
-static int uvedit_center(
- Scene *scene, Object **objects, uint objects_len, Image *ima, float center[2])
+static int uvedit_center(Scene *scene, Object **objects, uint objects_len, float center[2])
{
BMFace *f;
BMLoop *l;
@@ -75,7 +74,7 @@ static int uvedit_center(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -97,8 +96,10 @@ static int uvedit_center(
return tot;
}
-static void uvedit_translate(
- Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2])
+static void uvedit_translate(Scene *scene,
+ Object **objects,
+ uint objects_len,
+ const float delta[2])
{
BMFace *f;
BMLoop *l;
@@ -112,7 +113,7 @@ static void uvedit_translate(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -134,7 +135,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2];
int imx, imy, step, digits;
float width = 8 * UI_UNIT_X;
@@ -144,7 +144,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
ED_space_image_get_size(sima, &imx, &imy);
- if (uvedit_center(scene, objects, objects_len, ima, center)) {
+ if (uvedit_center(scene, objects, objects_len, center)) {
float range_xy[2][2] = {
{-10.0f, 10.0f},
{-10.0f, 10.0f},
@@ -212,7 +212,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2], delta[2];
int imx, imy;
@@ -225,7 +224,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len);
ED_space_image_get_size(sima, &imx, &imy);
- uvedit_center(scene, objects, objects_len, ima, center);
+ uvedit_center(scene, objects, objects_len, center);
if (sima->flag & SI_COORDFLOATS) {
delta[0] = uvedit_old_center[0] - center[0];
@@ -236,7 +235,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
delta[1] = uvedit_old_center[1] / imy - center[1];
}
- uvedit_translate(scene, objects, objects_len, ima, delta);
+ uvedit_translate(scene, objects, objects_len, delta);
WM_event_add_notifier(C, NC_IMAGE, sima->image);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 959ca1eeef1..f8cef95c776 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -216,13 +216,14 @@ static void uvedit_get_batches(Object *ob,
}
}
-static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
+static void draw_uvs_shadow(SpaceImage *sima,
const Scene *scene,
Object *obedit,
Depsgraph *depsgraph)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
Mesh *me = ob_eval->data;
+ const float overlay_alpha = sima->uv_opacity;
float col[4];
UI_GetThemeColor4fv(TH_UV_SHADOW, col);
@@ -231,9 +232,26 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false);
if (edges) {
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
+ col[3] = overlay_alpha;
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(edges, "color", col);
GPU_batch_draw(edges);
+
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index ffab5bd094f..31384d6df17 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -57,13 +57,11 @@ typedef struct UvNearestHit {
}
bool uv_find_nearest_vert(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
const float penalty_dist,
struct UvNearestHit *hit_final);
bool uv_find_nearest_vert_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -71,24 +69,20 @@ bool uv_find_nearest_vert_multi(struct Scene *scene,
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -116,14 +110,11 @@ void UV_OT_stitch(struct wmOperatorType *ot);
/* uvedit_select.c */
-bool uvedit_select_is_any_selected(struct Scene *scene, struct Image *ima, struct Object *obedit);
+bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
bool uvedit_select_is_any_selected_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len);
const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
- struct Object *obedit,
- struct Image *ima,
struct BMVert *eve,
const int cd_loop_uv_offset);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index a99e05cb52b..78b6cfc44ac 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -252,12 +252,8 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float r_min[2],
- float r_max[2])
+bool ED_uvedit_minmax_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
{
bool changed = false;
INIT_MINMAX2(r_min, r_max);
@@ -274,7 +270,7 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -290,10 +286,9 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
return changed;
}
-bool ED_uvedit_minmax(
- const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
{
- return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
+ return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
/* Be careful when using this, it bypasses all synchronization options */
@@ -314,8 +309,10 @@ void ED_uvedit_select_all(BMesh *bm)
}
}
-static bool ED_uvedit_median_multi(
- const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+static bool ED_uvedit_median_multi(const Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ float co[2])
{
uint sel = 0;
zero_v2(co);
@@ -332,7 +329,7 @@ static bool ED_uvedit_median_multi(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -351,24 +348,20 @@ static bool ED_uvedit_median_multi(
return (sel != 0);
}
-bool ED_uvedit_center_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float cent[2],
- char mode)
+bool ED_uvedit_center_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
{
bool changed = false;
if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
float min[2], max[2];
- if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
+ if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) {
mid_v2_v2v2(cent, min, max);
changed = true;
}
}
else {
- if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
+ if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) {
changed = true;
}
}
@@ -392,8 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- *r_has_select = uvedit_select_is_any_selected_multi(
- scene, sima->image, objects, objects_len);
+ *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len);
MEM_freeN(objects);
}
break;
@@ -402,7 +394,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- changed = ED_uvedit_center_multi(scene, sima->image, objects, objects_len, r_center, mode);
+ changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode);
MEM_freeN(objects);
if (r_has_select != NULL) {
*r_has_select = changed;
@@ -440,7 +432,6 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
@@ -467,7 +458,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -482,7 +473,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
}
- ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
+ ED_uvedit_center_multi(scene, objects, objects_len, cent, 0);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -501,7 +492,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -521,7 +512,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -548,7 +539,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* tag verts with a selected UV */
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -619,9 +610,9 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* we know the returns from these must be valid */
const float *uv_start = uvedit_first_selected_uv_from_vertex(
- scene, obedit, ima, eve_line[0], cd_loop_uv_offset);
+ scene, eve_line[0], cd_loop_uv_offset);
const float *uv_end = uvedit_first_selected_uv_from_vertex(
- scene, obedit, ima, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
+ scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
/* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
float a = 0.0f;
eUVWeldAlign tool_local = tool;
@@ -646,7 +637,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* go over all verts except for endpoints */
for (i = 0; i < BLI_array_len(eve_line); i++) {
BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -754,7 +745,6 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -808,7 +798,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -899,7 +889,6 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -939,7 +928,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -972,7 +961,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1086,10 +1075,12 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima)
uv_snap_to_pixel(sima->cursor, width, height);
}
-static bool uv_snap_cursor_to_selection(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
+static bool uv_snap_cursor_to_selection(Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ SpaceImage *sima)
{
- return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
+ return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
@@ -1105,13 +1096,12 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
break;
case 1: {
Scene *scene = CTX_data_scene(C);
- Image *ima = CTX_data_edit_image(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
+ changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima);
MEM_freeN(objects);
break;
}
@@ -1155,7 +1145,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
/** \name Snap Selection Operator
* \{ */
-static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
+static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -1167,7 +1157,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1183,7 +1173,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
return changed;
}
-static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2])
+static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -1195,7 +1185,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1211,7 +1201,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
return changed;
}
-static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
+static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -1225,7 +1215,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
/* index every vert that has a selected UV using it, but only once so as to
* get unique indices and to count how much to malloc */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (uvedit_face_visible_test(scene, f)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
@@ -1269,7 +1259,6 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Image *ima = sima->image;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1285,7 +1274,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
h = (float)height;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1307,7 +1296,6 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
const int target = RNA_enum_get(op->ptr, "target");
@@ -1319,7 +1307,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
if (target == 2) {
float center[2];
- if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
+ if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
@@ -1341,13 +1329,13 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
break;
case 1:
- changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
+ changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor);
break;
case 2:
- changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
+ changed = uv_snap_uvs_offset(scene, obedit, offset);
break;
case 3:
- changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+ changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit);
break;
}
@@ -1398,7 +1386,6 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1423,7 +1410,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1501,11 +1488,9 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop
static int uv_hide_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
const bool swap = RNA_boolean_get(op->ptr, "unselected");
- Image *ima = sima ? sima->image : NULL;
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
uint objects_len = 0;
@@ -1532,7 +1517,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
int hide = 0;
- if (!uvedit_face_visible_test(scene, ob, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2006,8 +1991,6 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima ? sima->image : NULL;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const ToolSettings *ts = scene->toolsettings;
@@ -2038,7 +2021,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, ob, ima, efa)) {
+ if (uvedit_face_visible_test(scene, efa)) {
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 6e931b56a85..cc9be9d48c1 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -70,9 +70,11 @@
#include "uvedit_intern.h"
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action);
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action);
static void uv_select_flush_from_tag_face(SpaceImage *sima,
Scene *scene,
Object *obedit,
@@ -112,7 +114,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em,
}
}
-bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
+bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
{
if (ts->uv_flag & UV_SYNC_SELECTION) {
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
@@ -121,25 +123,9 @@ bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
}
}
-bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
+bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
{
- return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
-}
-
-bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
-{
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
- Image *face_image;
- ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
- return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
- }
- else {
- return uvedit_face_visible_nolocal_ex(ts, efa);
- }
-}
-bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
-{
- return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
+ return uvedit_face_visible_test_ex(scene->toolsettings, efa);
}
bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
@@ -437,8 +423,7 @@ void uvedit_uv_select_disable(BMEditMesh *em,
/** \name Find Nearest Elements
* \{ */
-bool uv_find_nearest_edge(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
+bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -453,7 +438,7 @@ bool uv_find_nearest_edge(
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -479,7 +464,6 @@ bool uv_find_nearest_edge(
}
bool uv_find_nearest_edge_multi(Scene *scene,
- Image *ima,
Object **objects,
const uint objects_len,
const float co[2],
@@ -488,7 +472,7 @@ bool uv_find_nearest_edge_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
+ if (uv_find_nearest_edge(scene, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -496,8 +480,7 @@ bool uv_find_nearest_edge_multi(Scene *scene,
return found;
}
-bool uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
+bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool found = false;
@@ -507,7 +490,7 @@ bool uv_find_nearest_face(
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
hit.luv = hit.luv_next = NULL;
@@ -516,7 +499,7 @@ bool uv_find_nearest_face(
BMFace *efa;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -539,7 +522,6 @@ bool uv_find_nearest_face(
}
bool uv_find_nearest_face_multi(Scene *scene,
- Image *ima,
Object **objects,
const uint objects_len,
const float co[2],
@@ -548,7 +530,7 @@ bool uv_find_nearest_face_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
+ if (uv_find_nearest_face(scene, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -567,7 +549,6 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_
}
bool uv_find_nearest_vert(Scene *scene,
- Image *ima,
Object *obedit,
float const co[2],
const float penalty_dist,
@@ -578,7 +559,7 @@ bool uv_find_nearest_vert(Scene *scene,
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
@@ -593,7 +574,7 @@ bool uv_find_nearest_vert(Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -639,7 +620,6 @@ bool uv_find_nearest_vert(Scene *scene,
}
bool uv_find_nearest_vert_multi(Scene *scene,
- Image *ima,
Object **objects,
const uint objects_len,
float const co[2],
@@ -649,7 +629,7 @@ bool uv_find_nearest_vert_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
+ if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -657,12 +637,8 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
-bool ED_uvedit_nearest_uv(const Scene *scene,
- Object *obedit,
- Image *ima,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
+bool ED_uvedit_nearest_uv(
+ const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMIter iter;
@@ -671,7 +647,7 @@ bool ED_uvedit_nearest_uv(const Scene *scene,
float dist_best = *dist_sq;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
BMLoop *l_iter, *l_first;
@@ -697,7 +673,6 @@ bool ED_uvedit_nearest_uv(const Scene *scene,
}
bool ED_uvedit_nearest_uv_multi(const Scene *scene,
- Image *ima,
Object **objects,
const uint objects_len,
const float co[2],
@@ -707,7 +682,7 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
+ if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
found = true;
}
}
@@ -817,12 +792,8 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
return true;
}
-static int uv_select_edgeloop(Scene *scene,
- Image *ima,
- Object *obedit,
- UvNearestHit *hit,
- const float limit[2],
- const bool extend)
+static int uv_select_edgeloop(
+ Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -843,7 +814,7 @@ static int uv_select_edgeloop(Scene *scene,
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
}
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
@@ -867,8 +838,7 @@ static int uv_select_edgeloop(Scene *scene,
/* find correct valence edges which are not tagged yet, but connect to tagged one */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
- uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
/* check face not hidden and not tagged */
if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
@@ -930,7 +900,6 @@ static int uv_select_edgeloop(Scene *scene,
* \{ */
static void uv_select_linked_multi(Scene *scene,
- Image *ima,
Object **objects,
const uint objects_len,
const float limit[2],
@@ -980,7 +949,7 @@ static void uv_select_linked_multi(Scene *scene,
if (hit_final == NULL) {
/* Use existing selection */
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (uvedit_face_visible_test(scene, efa)) {
if (select_faces) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
@@ -1121,14 +1090,15 @@ static void uv_select_linked_multi(Scene *scene,
* \warning This returns first selected UV,
* not ideal in many cases since there could be multiple.
*/
-const float *uvedit_first_selected_uv_from_vertex(
- Scene *scene, Object *obedit, Image *ima, BMVert *eve, const int cd_loop_uv_offset)
+const float *uvedit_first_selected_uv_from_vertex(Scene *scene,
+ BMVert *eve,
+ const int cd_loop_uv_offset)
{
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -1151,7 +1121,6 @@ static int uv_select_more_less(bContext *C, const bool select)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
SpaceImage *sima = CTX_wm_space_image(C);
BMFace *efa;
@@ -1193,7 +1162,7 @@ static int uv_select_more_less(bContext *C, const bool select)
/* mark loops to be selected */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (uvedit_face_visible_test(scene, efa)) {
#define IS_SEL 1
#define IS_UNSEL 2
@@ -1233,7 +1202,7 @@ static int uv_select_more_less(bContext *C, const bool select)
/* mark loops to be selected */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (uvedit_face_visible_test(scene, efa)) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -1308,7 +1277,7 @@ void UV_OT_select_less(wmOperatorType *ot)
/** \name (De)Select All Operator
* \{ */
-bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
+bool uvedit_select_is_any_selected(Scene *scene, Object *obedit)
{
const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1323,7 +1292,7 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
else {
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1337,15 +1306,12 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
return false;
}
-bool uvedit_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len)
+bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len)
{
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (uvedit_select_is_any_selected(scene, ima, obedit)) {
+ if (uvedit_select_is_any_selected(scene, obedit)) {
found = true;
break;
}
@@ -1353,7 +1319,7 @@ bool uvedit_select_is_any_selected_multi(Scene *scene,
return found;
}
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action)
{
const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1365,7 +1331,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (action == SEL_TOGGLE) {
- action = uvedit_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
+ action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT;
}
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -1387,7 +1353,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int
}
else {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1410,17 +1376,19 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int
}
}
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action)
{
if (action == SEL_TOGGLE) {
- action = uvedit_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
- SEL_SELECT;
+ action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT :
+ SEL_SELECT;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- uv_select_all_perform(scene, ima, obedit, action);
+ uv_select_all_perform(scene, obedit, action);
}
}
@@ -1429,7 +1397,6 @@ static int uv_select_all_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
@@ -1438,7 +1405,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
+ uv_select_all_perform_multi(scene, objects, objects_len, action);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -1510,7 +1477,6 @@ static int uv_mouse_select_multi(bContext *C,
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1563,12 +1529,11 @@ static int uv_mouse_select_multi(bContext *C,
/* find nearest element */
if (loop) {
/* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
- found_item = uv_find_nearest_vert_multi(
- scene, ima, objects, objects_len, co, penalty_dist, &hit);
+ found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -1585,7 +1550,7 @@ static int uv_mouse_select_multi(bContext *C,
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -1604,7 +1569,7 @@ static int uv_mouse_select_multi(bContext *C,
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
- found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -1628,13 +1593,13 @@ static int uv_mouse_select_multi(bContext *C,
}
}
else if (selectmode == UV_SELECT_ISLAND) {
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
}
if (!found_item) {
if (deselect_all) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -1654,19 +1619,18 @@ static int uv_mouse_select_multi(bContext *C,
if (loop) {
if (!extend) {
/* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
- flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
+ flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
if (!extend) {
/* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
/* Current behavior of 'extend'
* is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
+ uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -1701,7 +1665,7 @@ static int uv_mouse_select_multi(bContext *C,
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1719,7 +1683,7 @@ static int uv_mouse_select_multi(bContext *C,
}
else {
/* deselect all */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
if (selectmode == UV_SELECT_VERTEX) {
/* select vertex */
@@ -1739,7 +1703,7 @@ static int uv_mouse_select_multi(bContext *C,
/* select sticky uvs */
if (sticky != SI_STICKY_DISABLE) {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1946,7 +1910,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
float limit[2];
bool extend = true;
bool deselect = false;
@@ -1986,18 +1949,17 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
}
if (!extend) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
uv_select_linked_multi(scene,
- ima,
objects,
objects_len,
limit,
@@ -2117,7 +2079,6 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
@@ -2147,7 +2108,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
bool is_sel = false;
bool is_unsel = false;
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2483,7 +2444,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
const ARegion *region = CTX_wm_region(C);
BMFace *efa;
BMLoop *l;
@@ -2518,7 +2478,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
view_layer, ((View3D *)NULL), &objects_len);
if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
/* don't indent to avoid diff noise! */
@@ -2539,7 +2499,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
/* assume not touched */
BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (uvedit_face_visible_test(scene, efa)) {
uv_poly_center(efa, cent, cd_loop_uv_offset);
if (BLI_rctf_isect_pt_v(&rectf, cent)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
@@ -2558,7 +2518,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2594,7 +2554,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
bool has_selected = false;
@@ -2623,7 +2583,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
.efa = efa,
};
uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
}
}
@@ -2708,7 +2668,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const ToolSettings *ts = scene->toolsettings;
@@ -2757,7 +2716,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -2792,7 +2751,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2826,7 +2785,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
bool has_selected = false;
@@ -2847,7 +2806,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
.efa = efa,
};
uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
}
}
@@ -2920,7 +2879,6 @@ static bool do_lasso_select_mesh_uv(bContext *C,
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
@@ -2952,7 +2910,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
view_layer, ((View3D *)NULL), &objects_len);
if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
/* don't indent to avoid diff noise! */
@@ -2988,7 +2946,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -3025,7 +2983,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
bool has_selected = false;
@@ -3047,7 +3005,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
.efa = efa,
};
uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
}
}
@@ -3116,7 +3074,6 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -3134,7 +3091,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = false;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -3208,7 +3165,6 @@ static int uv_select_overlap(bContext *C, const bool extend)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -3224,13 +3180,13 @@ static int uv_select_overlap(bContext *C, const bool extend)
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
}
BMIter iter;
BMFace *efa;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
continue;
}
uv_tri_len += efa->len - 2;
@@ -3261,7 +3217,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
int face_index;
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
continue;
}
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 3a4f12acf9c..594847b7249 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -2550,12 +2550,11 @@ static StitchState *stitch_select(bContext *C,
float co[2];
UvNearestHit hit = UV_NEAREST_HIT_INIT;
ARegion *region = CTX_wm_region(C);
- Image *ima = CTX_data_edit_image(C);
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
if (ssc->mode == STITCH_VERT) {
- if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
+ if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
/* Add vertex to selection, deselect all common uv's of vert other than selected and
* update the preview. This behavior was decided so that you can do stuff like deselect
* the opposite stitchable vertex and the initial still gets deselected */
@@ -2576,7 +2575,7 @@ static StitchState *stitch_select(bContext *C,
return state;
}
}
- else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
+ else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) {
/* find StitchState from hit->ob */
StitchState *state = NULL;
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {