diff options
author | YimingWu <xp8110@outlook.com> | 2020-05-30 11:34:11 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2020-05-30 11:34:11 +0300 |
commit | 3b52dfe549f0c2fca7e0cd499b85fb098e9b4da9 (patch) | |
tree | 668b6b25da0efdb87058b197084094181fb0c09f /source/blender/editors | |
parent | cd54abd2c1316136753f7bbe227bd762a5f9e7d9 (diff) | |
parent | 2ee94c954d6700a45fde320f330964bcf1888545 (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')
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( + ®ion_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, ®ion->uiblocks) { + if (STREQ(block->name, block_name)) { + BLI_remlink(®ion->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, ®ion->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, ®ion->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, ®ion->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, ®ion->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, ®ion->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, ®ion->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(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->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(®ion->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 = ®ion->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(®ion->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, ®ion->panels, pt, panel, w, em, vertical); + ed_panel_draw(C, + area, + region, + ®ion->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, ®ion->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, + ®ion->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(®ion->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++) { |