diff options
Diffstat (limited to 'source/blender/editors/space_view3d')
18 files changed, 1952 insertions, 547 deletions
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index c7fe82e0cbb..f2536cfac62 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 d469faac934..5daba238293 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -88,9 +88,9 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C) RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d == NULL) { - ScrArea *sa = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_VIEW3D) { - ARegion *region = BKE_area_find_region_active_win(sa); + ScrArea *area = CTX_wm_area(C); + if (area && area->spacetype == SPACE_VIEW3D) { + ARegion *region = BKE_area_find_region_active_win(area); if (region) { rv3d = region->regiondata; } @@ -101,27 +101,27 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C) /* ideally would return an rv3d but in some cases the region is needed too * so return that, the caller can then access the region->regiondata */ -bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar) +bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); *r_v3d = NULL; - *r_ar = NULL; + *r_region = NULL; - if (sa && sa->spacetype == SPACE_VIEW3D) { + if (area && area->spacetype == SPACE_VIEW3D) { ARegion *region = CTX_wm_region(C); - View3D *v3d = (View3D *)sa->spacedata.first; + View3D *v3d = (View3D *)area->spacedata.first; if (region) { RegionView3D *rv3d; if ((region->regiontype == RGN_TYPE_WINDOW) && (rv3d = region->regiondata) && (rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) { *r_v3d = v3d; - *r_ar = region; + *r_region = region; return true; } else { - if (ED_view3d_area_user_region(sa, v3d, r_ar)) { + if (ED_view3d_area_user_region(area, v3d, r_region)) { *r_v3d = v3d; return true; } @@ -136,23 +136,24 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar) * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup. * Also works if \a v3d is not the active space. */ -bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **r_ar) +bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region) { RegionView3D *rv3d = NULL; - ARegion *ar_unlock_user = NULL; - ARegion *ar_unlock = NULL; - const ListBase *region_list = (v3d == sa->spacedata.first) ? &sa->regionbase : &v3d->regionbase; + ARegion *region_unlock_user = NULL; + ARegion *region_unlock = NULL; + const ListBase *region_list = (v3d == area->spacedata.first) ? &area->regionbase : + &v3d->regionbase; BLI_assert(v3d->spacetype == SPACE_VIEW3D); - for (ARegion *region = region_list->first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, region_list) { /* find the first unlocked rv3d */ if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) { rv3d = region->regiondata; if ((rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) { - ar_unlock = region; + region_unlock = region; if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) { - ar_unlock_user = region; + region_unlock_user = region; break; } } @@ -160,13 +161,13 @@ bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion ** } /* camera/perspective view get priority when the active region is locked */ - if (ar_unlock_user) { - *r_ar = ar_unlock_user; + if (region_unlock_user) { + *r_region = region_unlock_user; return true; } - if (ar_unlock) { - *r_ar = ar_unlock; + if (region_unlock) { + *r_region = region_unlock; return true; } @@ -237,16 +238,19 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *region) RE_engine_free(rv3d->render_engine); rv3d->render_engine = NULL; } + + /* A bit overkill but this make sure the viewport is reset completely. (fclem) */ + WM_draw_region_free(region, false); } -void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) +void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *area) { wmWindowManager *wm = bmain->wm.first; if (v3d->shading.type != OB_RENDER) { ARegion *region; - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if ((region->regiontype == RGN_TYPE_WINDOW) && region->regiondata) { ED_view3d_stop_render_preview(wm, region); break; @@ -257,7 +261,7 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) /* ******************** default callbacks for view3d space ***************** */ -static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) +static SpaceLink *view3d_new(const ScrArea *UNUSED(area), const Scene *scene) { ARegion *region; View3D *v3d; @@ -336,7 +340,7 @@ static void view3d_free(SpaceLink *sl) } /* spacetype; init callback */ -static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa)) +static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area)) { } @@ -500,6 +504,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); } @@ -561,9 +567,9 @@ static void *view3d_main_region_duplicate(void *poin) } static void view3d_main_region_listener( - wmWindow *UNUSED(win), ScrArea *sa, ARegion *region, wmNotifier *wmn, const Scene *scene) + wmWindow *UNUSED(win), ScrArea *area, ARegion *region, wmNotifier *wmn, const Scene *scene) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; RegionView3D *rv3d = region->regiondata; wmGizmoMap *gzmap = region->gizmo_map; @@ -756,7 +762,7 @@ static void view3d_main_region_listener( } break; case NC_LIGHTPROBE: - ED_area_tag_refresh(sa); + ED_area_tag_refresh(area); break; case NC_IMAGE: /* this could be more fine grained checks if we had @@ -821,7 +827,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), struct bScreen *UNUSED(screen), - struct ScrArea *sa, + struct ScrArea *area, struct ARegion *region, struct wmMsgBus *mbus) { @@ -899,7 +905,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, { wmMsgSubscribeValue msg_sub_value_region_tag_refresh = { .owner = region, - .user_data = sa, + .user_data = area, .notify = WM_toolsystem_do_msg_notify_tag_refresh, }; WM_msg_subscribe_rna_anon_prop(mbus, Object, mode, &msg_sub_value_region_tag_refresh); @@ -907,9 +913,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, } } -static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *region) +/* 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, sa, 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); } } @@ -930,7 +946,7 @@ static void view3d_header_region_draw(const bContext *C, ARegion *region) } static void view3d_header_region_listener(wmWindow *UNUSED(win), - ScrArea *UNUSED(sa), + ScrArea *UNUSED(area), ARegion *region, wmNotifier *wmn, const Scene *UNUSED(scene)) @@ -1003,7 +1019,7 @@ static void view3d_header_region_message_subscribe(const struct bContext *UNUSED struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), struct bScreen *UNUSED(screen), - struct ScrArea *UNUSED(sa), + struct ScrArea *UNUSED(area), struct ARegion *region, struct wmMsgBus *mbus) { @@ -1147,7 +1163,7 @@ static void view3d_buttons_region_layout(const bContext *C, ARegion *region) } static void view3d_buttons_region_listener(wmWindow *UNUSED(win), - ScrArea *UNUSED(sa), + ScrArea *UNUSED(area), ARegion *region, wmNotifier *wmn, const Scene *UNUSED(scene)) @@ -1270,11 +1286,11 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region) /* area (not region) level listener */ static void space_view3d_listener(wmWindow *UNUSED(win), - ScrArea *sa, + ScrArea *area, struct wmNotifier *wmn, Scene *UNUSED(scene)) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; /* context changes */ switch (wmn->category) { @@ -1282,7 +1298,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), switch (wmn->data) { case ND_WORLD: if (v3d->flag2 & V3D_HIDE_OVERLAYS) { - ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); + ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW); } break; } @@ -1292,7 +1308,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), case ND_WORLD_DRAW: case ND_WORLD: if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) { - ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); + ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW); } break; } @@ -1301,7 +1317,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), switch (wmn->data) { case ND_NODES: if (v3d->shading.type == OB_TEXTURE) { - ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); + ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW); } break; } @@ -1309,7 +1325,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), } } -static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa)) +static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area)) { Scene *scene = CTX_data_scene(C); LightCache *lcache = scene->eevee.light_cache_data; @@ -1367,7 +1383,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes return -1; /* found but not available */ } -static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id) +static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id) { View3D *v3d; ARegion *region; @@ -1382,8 +1398,8 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i v3d->camera = (Object *)new_id; if (!new_id) { /* 3D view might be inactive, in that case needs to use slink->regionbase */ - ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase : - &slink->regionbase; + ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase : + &slink->regionbase; for (region = regionbase->first; region; region = region->next) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd : diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 80ab18cd3db..cb87ddafea1 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1005,7 +1005,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } } BKE_nurb_test_2d(nu); - BKE_nurb_handles_test(nu, true); /* test for bezier too */ + BKE_nurb_handles_test(nu, true, false); /* test for bezier too */ nu = nu->next; } @@ -1140,9 +1140,9 @@ static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt)) return false; } -static void view3d_panel_vgroup(const bContext *C, Panel *pa) +static void view3d_panel_vgroup(const bContext *C, Panel *panel) { - uiBlock *block = uiLayoutAbsoluteBlock(pa->layout); + uiBlock *block = uiLayoutAbsoluteBlock(panel->layout); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = view_layer->basact->object; @@ -1171,7 +1171,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL); - bcol = uiLayoutColumn(pa->layout, true); + bcol = uiLayoutColumn(panel->layout, true); row = uiLayoutRow(bcol, true); /* The filter button row */ RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr); @@ -1269,7 +1269,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) yco -= 2; - col = uiLayoutColumn(pa->layout, true); + col = uiLayoutColumn(panel->layout, true); row = uiLayoutRow(col, true); ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1); @@ -1555,7 +1555,7 @@ static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt) return (view_layer->basact != NULL); } -static void view3d_panel_transform(const bContext *C, Panel *pa) +static void view3d_panel_transform(const bContext *C, Panel *panel) { uiBlock *block; ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1563,10 +1563,10 @@ static void view3d_panel_transform(const bContext *C, Panel *pa) Object *obedit = OBEDIT_FROM_OBACT(ob); uiLayout *col; - block = uiLayoutGetBlock(pa->layout); + block = uiLayoutGetBlock(panel->layout); UI_block_func_handle_set(block, do_view3d_region_buttons, NULL); - col = uiLayoutColumn(pa->layout, false); + col = uiLayoutColumn(panel->layout, false); if (ob == obedit) { if (ob->type == OB_ARMATURE) { @@ -1577,9 +1577,7 @@ static void view3d_panel_transform(const bContext *C, Panel *pa) } 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) { @@ -1644,7 +1642,7 @@ static int view3d_object_mode_menu(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) { - ED_object_mode_toggle(C, OB_MODE_POSE); + ED_object_mode_set(C, (ob->mode == OB_MODE_OBJECT) ? OB_MODE_POSE : OB_MODE_OBJECT); return OPERATOR_CANCELLED; } else { diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 694cb7ee7d4..fac378ae104 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -63,6 +63,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_info.h" #include "ED_keyframing.h" #include "ED_screen.h" #include "ED_screen_types.h" @@ -101,6 +102,8 @@ #define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f +#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit) + /* -------------------------------------------------------------------- */ /** \name General Functions * \{ */ @@ -1341,7 +1344,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr)); @@ -1473,7 +1476,7 @@ static void draw_selected_name( BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info)); BLF_disable(font_id, BLF_SHADOW); @@ -1494,7 +1497,7 @@ static void draw_grid_unit_name( BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); } - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_enable(font_id, BLF_SHADOW); BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); @@ -1515,6 +1518,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); #ifdef WITH_INPUT_NDOF if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) && @@ -1550,8 +1555,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) } } - int xoffset = rect->xmin + U.widget_unit; - int yoffset = rect->ymax; + int xoffset = rect->xmin + (0.5f * U.widget_unit); + int yoffset = rect->ymax - (0.1f * U.widget_unit); if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { @@ -1562,7 +1567,6 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) } if (U.uiflag & USER_DRAWVIEWINFO) { - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); draw_selected_name(scene, view_layer, ob, xoffset, &yoffset); } @@ -1571,10 +1575,12 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) /* draw below the viewport name */ draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset); } + + DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT); } - if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { - DRW_draw_region_engine_info(xoffset, yoffset); + if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) { + ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT); } BLF_batch_draw_end(); @@ -2217,7 +2223,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { GPUViewport *viewport = WM_draw_region_get_viewport(region); - DRW_draw_depth_object(vc->region, vc->v3d, viewport, obact_eval); + DRW_draw_depth_object(vc->scene, vc->region, vc->v3d, viewport, obact_eval); } vc->v3d->flag &= ~V3D_INVALID_BACKBUF; @@ -2396,9 +2402,9 @@ void ED_view3d_screen_datamask(const bContext *C, CustomData_MeshMasks_update(r_cddata_masks, &CD_MASK_BAREMESH); /* Check if we need tfaces & mcols due to view mode. */ - for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - ED_view3d_datamask(C, scene, sa->spacedata.first, r_cddata_masks); + LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_VIEW3D) { + ED_view3d_datamask(C, scene, area->spacedata.first, r_cddata_masks); } } } @@ -2493,7 +2499,7 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset) BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; #ifdef WITH_INTERNATIONAL BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable)); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 67dacca85ba..edd75d8e561 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -175,7 +175,7 @@ typedef struct ViewOpsData { /** Context pointers (assigned by #viewops_data_alloc). */ Main *bmain; Scene *scene; - ScrArea *sa; + ScrArea *area; ARegion *region; View3D *v3d; RegionView3D *rv3d; @@ -277,9 +277,9 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) vod->bmain = CTX_data_main(C); vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); vod->scene = CTX_data_scene(C); - vod->sa = CTX_wm_area(C); + vod->area = CTX_wm_area(C); vod->region = CTX_wm_region(C); - vod->v3d = vod->sa->spacedata.first; + vod->v3d = vod->area->spacedata.first; vod->rv3d = vod->region->regiondata; } @@ -529,10 +529,10 @@ static void viewops_data_create(bContext *C, negate_v3_v3(rv3d->ofs, dvec); } else { - const float mval_ar_mid[2] = {(float)vod->region->winx / 2.0f, - (float)vod->region->winy / 2.0f}; + const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f, + (float)vod->region->winy / 2.0f}; - ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_ar_mid, rv3d->ofs); + ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs); negate_v3(rv3d->ofs); } negate_v3(vod->dyn_ofs); @@ -627,14 +627,14 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Rotate Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items); /* disabled mode switching for now, can re-implement better, later on */ #if 0 @@ -1120,7 +1120,7 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) * often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho. */ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, - ScrArea *sa, + ScrArea *area, ARegion *region, const bool has_translate, const bool has_zoom) @@ -1161,7 +1161,7 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, /* all callers must check */ if (has_translate) { - BLI_assert(ED_view3d_offset_lock_check((View3D *)sa->spacedata.first, rv3d) == false); + BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false); } } @@ -1178,18 +1178,18 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, sub_v3_v3(rv3d->ofs, pan_vec); if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, region); + view3d_boxview_sync(area, region); } } } static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, - ScrArea *sa, + ScrArea *area, ARegion *region, ViewOpsData *vod, const bool apply_dyn_ofs) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; RegionView3D *rv3d = region->regiondata; float view_inv[4]; @@ -1422,12 +1422,12 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp; if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom); + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); xform_flag |= HAS_TRANSLATE; } if (has_rotation) { - view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, true); + view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true); xform_flag |= HAS_ROTATE; } } @@ -1505,7 +1505,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d); if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, true); + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true); xform_flag |= HAS_TRANSLATE; } } @@ -1535,7 +1535,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev if (!is_orbit_around_pivot) { ED_view3d_distance_set(rv3d, 0.0f); } - view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, is_orbit_around_pivot); + view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot); xform_flag |= HAS_ROTATE; if (!is_orbit_around_pivot) { ED_view3d_distance_set(rv3d, dist_backup); @@ -1543,7 +1543,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev } if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom); + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); xform_flag |= HAS_TRANSLATE; } } @@ -1607,11 +1607,11 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); if (ndof->progress != P_FINISHING) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, sa, region, has_translate, has_zoom); + view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom); xform_flag |= HAS_TRANSLATE; } } @@ -1702,14 +1702,14 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Move Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); @@ -1751,7 +1751,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) add_v3_v3(vod->rv3d->ofs, dvec); if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->sa, vod->region); + view3d_boxview_sync(vod->area, vod->region); } } @@ -1901,14 +1901,14 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Zoom Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items); /* disabled mode switching for now, can re-implement better, later on */ #if 0 @@ -2189,7 +2189,7 @@ static void viewzoom_apply_3d(ViewOpsData *vod, CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->sa, vod->region); + view3d_boxview_sync(vod->area, vod->region); } ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); @@ -2280,7 +2280,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); View3D *v3d; RegionView3D *rv3d; - ScrArea *sa; + ScrArea *area; ARegion *region; bool use_cam_zoom; float dist_range[2]; @@ -2291,15 +2291,15 @@ static int viewzoom_exec(bContext *C, wmOperator *op) if (op->customdata) { ViewOpsData *vod = op->customdata; - sa = vod->sa; + area = vod->area; region = vod->region; } else { - sa = CTX_wm_area(C); + area = CTX_wm_area(C); region = CTX_wm_region(C); } - v3d = sa->spacedata.first; + v3d = area->spacedata.first; rv3d = region->regiondata; use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && @@ -2342,7 +2342,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) } if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, region); + view3d_boxview_sync(area, region); } ED_view3d_depth_tag_update(rv3d); @@ -2472,14 +2472,14 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items); /* disabled mode switching for now, can re-implement better, later on */ #if 0 @@ -2538,7 +2538,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_ } if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->sa, vod->region); + view3d_boxview_sync(vod->area, vod->region); } ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); @@ -2603,7 +2603,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) { View3D *v3d; RegionView3D *rv3d; - ScrArea *sa; + ScrArea *area; ARegion *region; float mousevec[3]; @@ -2612,18 +2612,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op) if (op->customdata) { ViewOpsData *vod = op->customdata; - sa = vod->sa; + area = vod->area; region = vod->region; copy_v3_v3(mousevec, vod->init.mousevec); } else { - sa = CTX_wm_area(C); + area = CTX_wm_area(C); region = CTX_wm_region(C); negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]); normalize_v3(mousevec); } - v3d = sa->spacedata.first; + v3d = area->spacedata.first; rv3d = region->regiondata; const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); @@ -2636,7 +2636,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f); if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, region); + view3d_boxview_sync(area, region); } ED_view3d_depth_tag_update(rv3d); @@ -2886,9 +2886,9 @@ static void view3d_from_minmax_multi(bContext *C, const bool ok_dist, const int smooth_viewtx) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region; - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; /* when using all regions, don't jump out of camera view, @@ -2980,7 +2980,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->description = "View all objects in scene"; ot->idname = "VIEW3D_OT_view_all"; @@ -3349,7 +3349,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name View Camera Center Operator +/** \name Frame Camera Bounds Operator * \{ */ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3386,8 +3386,8 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_view_center_camera(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Camera Center"; - ot->description = "Center the camera view"; + ot->name = "Frame Camera Bounds"; + ot->description = "Center the camera view, resizing the view to fit its bounds"; ot->idname = "VIEW3D_OT_view_center_camera"; /* api callbacks */ @@ -4376,7 +4376,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) } if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->sa, vod->region); + view3d_boxview_sync(vod->area, vod->region); } ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); @@ -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; @@ -5279,7 +5278,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); View3D *v3d = CTX_wm_view3d(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); int type = RNA_enum_get(op->ptr, "type"); if (type == OB_SOLID) { @@ -5307,7 +5306,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op) } } - ED_view3d_shade_update(bmain, v3d, sa); + ED_view3d_shade_update(bmain, v3d, area); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; @@ -5340,7 +5339,7 @@ void VIEW3D_OT_toggle_shading(wmOperatorType *ot) static int toggle_xray_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); Object *obact = CTX_data_active_object(C); if (obact && ((obact->mode & OB_MODE_POSE) || @@ -5362,7 +5361,7 @@ static int toggle_xray_exec(bContext *C, wmOperator *op) } } - ED_area_tag_redraw(sa); + ED_area_tag_redraw(area); return OPERATOR_FINISHED; } @@ -5372,6 +5371,7 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot) /* identifiers */ ot->name = "Toggle X-Ray"; ot->idname = "VIEW3D_OT_toggle_xray"; + ot->description = "Transparent scene display. Allow selecting through items"; /* api callbacks */ ot->exec = toggle_xray_exec; diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 563e1afa67e..06d1a033a0d 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -125,14 +125,14 @@ void fly_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Fly Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Fly Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Fly Modal", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c index cc00037b1fb..533fba3795b 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -321,14 +321,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { gz = navgroup->gz_array[GZ_INDEX_CAMERA]; - gz->matrix_basis[3][0] = co[0]; - gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][0] = roundf(co[0]); + gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++)); WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); if (navgroup->state.rv3d.is_camera == false) { gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO]; - gz->matrix_basis[3][0] = co[0]; - gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][0] = roundf(co[0]); + gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++)); WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); } } 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 a8e8d8cee96..3ce4c8dc9a8 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -197,8 +197,8 @@ static void axis_geom_draw(const wmGizmo *gz, const bool select, const struct AxisDrawInfo *draw_info) { - - GPU_line_width(gz->line_width); + float viewport[4]; + GPU_viewport_size_get_f(viewport); GPUVertFormat *format = immVertexFormat(); const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -341,8 +341,13 @@ static void axis_geom_draw(const wmGizmo *gz, /* Axis Line. */ if (is_pos) { float v_start[3]; - GPU_line_width(2.0f); + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + immUniform2fv("viewportSize", &viewport[2]); + immUniform1f("lineWidth", 2.0f * U.pixelsize); immUniformColor4fv(is_pos_color ? color_current : color_current_fade); + immBegin(GPU_PRIM_LINES, 2); if (axis_align == -1) { zero_v3(v_start); @@ -358,6 +363,10 @@ static void axis_geom_draw(const wmGizmo *gz, immVertex3fv(pos_id, v_start); immVertex3fv(pos_id, v_final); immEnd(); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); } /* Axis Ball. */ @@ -527,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 4b194d6687d..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 *sa; + 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); @@ -299,7 +296,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2]) { - ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->region, r_co, xy, r_co); + ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co); } /* use for mousemove events */ @@ -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->sa->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 *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); + + ruler_info->wm = wm; ruler_info->win = win; - ruler_info->sa = sa; + 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_header.c b/source/blender/editors/space_view3d/view3d_header.c index 57989680705..829d793333e 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -77,7 +77,8 @@ static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op)) else { Scene *scene = CTX_data_scene(C); scene->display.shading.flag ^= V3D_SHADING_MATCAP_FLIP_X; - WM_event_add_notifier(C, NC_SCENE | NA_EDITED, v3d); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); } return OPERATOR_FINISHED; @@ -105,7 +106,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) wmWindow *win = CTX_wm_window(C); const int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift; - /* watch it: if sa->win does not exist, check that when calling direct drawing routines */ + /* watch it: if area->win does not exist, check that when calling direct drawing routines */ switch (event) { case B_SEL_VERT: @@ -138,10 +139,11 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) if (obedit && (obedit->type == OB_MESH)) { BMEditMesh *em = BKE_editmesh_from_object(obedit); uiLayout *row; + uiBut *but; row = uiLayoutRow(layout, true); block = uiLayoutGetBlock(row); - uiDefIconButBitS( + but = uiDefIconButBitS( block, UI_BTYPE_TOGGLE, SCE_SELECT_VERTEX, @@ -157,23 +159,26 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) 0, 0, TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection")); - uiDefIconButBitS(block, - UI_BTYPE_TOGGLE, - SCE_SELECT_EDGE, - B_SEL_EDGE, - ICON_EDGESEL, - 0, - 0, - ceilf(UI_UNIT_X - U.pixelsize), - UI_UNIT_Y, - &em->selectmode, - 1.0, - 0.0, - 0, - 0, - TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click " - "expands/contracts selection")); - uiDefIconButBitS( + UI_but_flag_disable(but, UI_BUT_UNDO); + but = uiDefIconButBitS( + block, + UI_BTYPE_TOGGLE, + SCE_SELECT_EDGE, + B_SEL_EDGE, + ICON_EDGESEL, + 0, + 0, + ceilf(UI_UNIT_X - U.pixelsize), + UI_UNIT_Y, + &em->selectmode, + 1.0, + 0.0, + 0, + 0, + TIP_("Edge select - Shift-Click for multiple modes, " + "Ctrl-Click expands/contracts selection depending on the current mode")); + UI_but_flag_disable(but, UI_BUT_UNDO); + but = uiDefIconButBitS( block, UI_BTYPE_TOGGLE, SCE_SELECT_FACE, @@ -189,6 +194,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) 0, 0, TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection")); + UI_but_flag_disable(but, UI_BUT_UNDO); } } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 610c40c37eb..50cd71d7edc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -91,8 +91,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot); void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot); -void view3d_boxview_copy(struct ScrArea *sa, struct ARegion *region); -void view3d_boxview_sync(struct ScrArea *sa, struct ARegion *region); +void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region); +void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region); void view3d_orbit_apply_dyn_ofs(float r_ofs[3], const float ofs_old[3], @@ -181,7 +181,7 @@ typedef struct V3D_SmoothParams { void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph, struct wmWindowManager *wm, struct wmWindow *win, - struct ScrArea *sa, + struct ScrArea *area, struct View3D *v3d, struct ARegion *region, const int smooth_viewtx, @@ -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 d8e1c8c1c72..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); @@ -388,7 +388,7 @@ void mesh_foreachScreenFace( BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) { + if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) { BKE_mesh_foreach_mapped_subdiv_face_center( me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); } @@ -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 a53262df267..0770bac1313 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -47,6 +47,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_transform.h" @@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_WINDOW, NULL); + ED_outliner_select_sync_from_object_tag(C); BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); @@ -209,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); @@ -232,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 8fdef585fa2..8c60e36a141 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -157,7 +157,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d) { bool changed = false; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (base->flag & BASE_SELECTED) { if (BASE_SELECTABLE(v3d, base)) { ED_object_base_select(base, BA_DESELECT); @@ -172,7 +172,7 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d) static bool object_deselect_all_except(ViewLayer *view_layer, Base *b) { bool changed = false; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (base->flag & BASE_SELECTED) { if (b != base) { ED_object_base_select(base, BA_DESELECT); @@ -408,9 +408,10 @@ typedef struct LassoSelectUserData { const rcti *rect; const rctf *rect_fl; rctf _rect_fl; - const int (*mcords)[2]; - int moves; + const int (*mcoords)[2]; + int mcoords_len; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ int pass; @@ -421,8 +422,8 @@ typedef struct LassoSelectUserData { static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, - const int (*mcords)[2], - const int moves, + const int (*mcoords)[2], + const int mcoords_len, const eSelectOp sel_op) { r_data->vc = vc; @@ -431,9 +432,11 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->rect_fl = &r_data->_rect_fl; BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); - r_data->mcords = mcords; - r_data->moves = moves; + 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; @@ -527,7 +530,8 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_point_done = true; } } @@ -536,22 +540,28 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_point_done = true; } } /* if one of points selected, we skip the bone itself */ - if ((is_point_done == true) || - ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) { + if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX))) { pchan->bone->flag |= BONE_DONE; } data->is_changed |= is_point_done; } } -static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves) +static void do_lasso_tag_pose(ViewContext *vc, + Object *ob, + const int mcoords[][2], + const int mcoords_len) { ViewContext vc_tmp; LassoSelectUserData data; @@ -564,9 +574,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] vc_tmp = *vc; vc_tmp.obact = ob; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0); ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); @@ -574,8 +584,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] } static bool do_lasso_select_objects(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { View3D *v3d = vc->v3d; @@ -591,7 +601,7 @@ static bool do_lasso_select_objects(ViewContext *vc, const bool is_select = base->flag & BASE_SELECTED; const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) && BLI_lasso_is_point_inside( - mcords, moves, base->sx, base->sy, IS_CLIPPED)); + mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); @@ -617,7 +627,7 @@ static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len) FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) { Object *ob_iter = base_iter->object; bArmature *arm = ob_iter->data; - for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) { Bone *bone = pchan->bone; bone->flag &= ~BONE_DONE; } @@ -659,7 +669,7 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const } bool changed = true; - for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) { Bone *bone = pchan->bone; if ((bone->flag & BONE_UNSELECTABLE) == 0) { const bool is_select = bone->flag & BONE_SELECTED; @@ -685,8 +695,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const } static bool do_lasso_select_pose(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { uint bases_len; @@ -695,7 +705,7 @@ static bool do_lasso_select_pose(ViewContext *vc, for (int i = 0; i < bases_len; i++) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; - do_lasso_tag_pose(vc, ob_iter, mcords, moves); + do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len); } const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); @@ -715,9 +725,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); @@ -746,8 +757,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -770,8 +783,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, } const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords, - data->moves, + const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); @@ -789,9 +802,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); @@ -801,8 +815,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, static bool do_lasso_select_mesh(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -812,9 +826,9 @@ static bool do_lasso_select_mesh(ViewContext *vc, /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -836,7 +850,7 @@ static bool do_lasso_select_mesh(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -892,27 +906,28 @@ 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; const bool is_inside = BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED); + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED); if (bp) { 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; @@ -922,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; } } @@ -930,24 +945,35 @@ static void do_lasso_select_curve__doSelect(void *userData, } static bool do_lasso_select_curve(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { + const bool deselect_all = (sel_op == SEL_OP_SET); LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + 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); } @@ -958,9 +984,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const { LassoSelectUserData *data = userData; const bool is_select = bp->f1 & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); 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); @@ -968,16 +995,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const } } static bool do_lasso_select_lattice(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -1002,7 +1029,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_a[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_inside_flag |= BONESEL_ROOT; } } @@ -1012,7 +1040,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_b[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_inside_flag |= BONESEL_TIP; } } @@ -1022,8 +1051,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (is_ignore_flag == 0) { if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX)) { is_inside_flag |= BONESEL_BONE; } } @@ -1033,16 +1065,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData, } static bool do_lasso_select_armature(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); @@ -1071,9 +1103,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData, { LassoSelectUserData *data = userData; const bool is_select = ml->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX)); 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(ml->flag, sel_op_result, SELECT); @@ -1081,8 +1114,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData, } } static bool do_lasso_select_meta(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -1090,9 +1123,9 @@ static bool do_lasso_select_meta(ViewContext *vc, MetaBall *mb = (MetaBall *)vc->obedit->data; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= BKE_mball_deselect_all(mb); @@ -1113,9 +1146,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = mv->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); 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(mv->flag, sel_op_result, SELECT); @@ -1124,8 +1158,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, } static bool do_lasso_select_paintvert(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); @@ -1143,7 +1177,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (use_zbuf) { @@ -1151,7 +1185,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -1163,7 +1197,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, else { LassoSelectUserData data; - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -1185,8 +1219,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc, } static bool do_lasso_select_paintface(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { Object *ob = vc->obact; @@ -1203,14 +1237,14 @@ static bool do_lasso_select_paintface(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (esel == NULL) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } if (esel->select_bitmap) { @@ -1224,9 +1258,9 @@ static bool do_lasso_select_paintface(ViewContext *vc, } #if 0 -static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op) +static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op) { - SpaceNode *snode = sa->spacedata.first; + SpaceNode *snode = area->spacedata.first; bNode *node; rcti rect; @@ -1234,7 +1268,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s float node_centf[2]; bool changed = false; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* store selection in temp test flag */ for (node = snode->edittree->nodes.first; node; node = node->next) { @@ -1244,7 +1278,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); const bool is_select = node->flag & SELECT; const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) && - BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])); + BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1])); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT); @@ -1257,8 +1291,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s } #endif -static bool view3d_lasso_select( - bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) +static bool view3d_lasso_select(bContext *C, + ViewContext *vc, + const int mcoords[][2], + const int mcoords_len, + const eSelectOp sel_op) { Object *ob = CTX_data_active_object(C); bool changed_multi = false; @@ -1268,26 +1305,26 @@ static bool view3d_lasso_select( if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { /* pass */ } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - changed_multi |= PE_lasso_select(C, mcords, moves, sel_op); + changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & OB_MODE_POSE)) { - changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_pose_bone_tag(C); } } else { - changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_object_tag(C); } @@ -1300,23 +1337,23 @@ static bool view3d_lasso_select( switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op); break; case OB_CURVE: case OB_SURF: - changed = do_lasso_select_curve(vc, mcords, moves, sel_op); + changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op); break; case OB_LATTICE: - changed = do_lasso_select_lattice(vc, mcords, moves, sel_op); + changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op); break; case OB_ARMATURE: - changed = do_lasso_select_armature(vc, mcords, moves, sel_op); + changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op); if (changed) { ED_outliner_select_sync_from_edit_bone_tag(C); } break; case OB_MBALL: - changed = do_lasso_select_meta(vc, mcords, moves, sel_op); + changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op); break; default: BLI_assert(!"lasso select on incorrect object type"); @@ -1342,10 +1379,10 @@ static bool view3d_lasso_select( static int view3d_lasso_select_exec(bContext *C, wmOperator *op) { ViewContext vc; - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); @@ -1354,9 +1391,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); + bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); if (changed_multi) { return OPERATOR_FINISHED; @@ -1663,20 +1700,31 @@ static int selectbuffer_ret_hits_5(uint *buffer, /** * Populate a select buffer with objects and bones, if there are any. * Checks three selection levels and compare. + * + * \param do_nearest_xray_if_supported: When set, read in hits that don't stop + * at the nearest surface. The hit's must still be ordered by depth. + * Needed so we can step to the next, non-active object when it's already selected, see: T76445. */ static int mixed_bones_object_selectbuffer(ViewContext *vc, uint *buffer, const int mval[2], eV3DSelectObjectFilter select_filter, - bool do_nearest) + bool do_nearest, + bool do_nearest_xray_if_supported) { rcti rect; int hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); + int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); int hits = 0; + if (do_nearest_xray_if_supported) { + if ((U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0) { + select_mode = VIEW3D_SELECT_PICK_ALL; + } + } + /* we _must_ end cache before return, use 'goto finally' */ view3d_opengl_select_cache_begin(); @@ -1780,7 +1828,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, do_nearest = do_nearest && !enumerate; - int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest); + int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true); return hits; } @@ -1912,7 +1960,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) const bool do_nearest = !XRAY_ACTIVE(vc.v3d); const int hits = mixed_bones_object_selectbuffer( - &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest); + &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); @@ -1971,7 +2019,7 @@ static bool ed_object_select_pick(bContext *C, /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); @@ -2526,6 +2574,7 @@ typedef struct BoxSelectUserData { const rctf *rect_fl; rctf _rect_fl; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ bool is_done; @@ -2544,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; @@ -2674,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; @@ -2683,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; @@ -2703,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; } } @@ -2711,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; @@ -3076,7 +3139,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const const int hits = view3d_opengl_select( vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); - for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { base->object->id.tag &= ~LIB_TAG_DOIT; } @@ -3092,7 +3155,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const goto finally; } - for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { if (BASE_SELECTABLE(v3d, base)) { if ((base->object->runtime.select_id & 0x0000FFFF) != 0) { BLI_array_append(bases, base); @@ -3104,9 +3167,9 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { - Bone *bone; - Base *base = ED_armature_base_and_bone_from_select_buffer( - bases, BLI_array_len(bases), *col, &bone); + bPoseChannel *pchan_dummy; + Base *base = ED_armature_base_and_pchan_from_select_buffer( + bases, BLI_array_len(bases), *col, &pchan_dummy); if (base != NULL) { base->object->id.tag |= LIB_TAG_DOIT; } @@ -3360,6 +3423,7 @@ typedef struct CircleSelectUserData { float mval_fl[2]; float radius; float radius_squared; + eBezTriple_Flag select_flag; /* runtime */ bool is_changed; @@ -3380,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; } @@ -3617,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; @@ -3650,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 2637fb6d1db..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, @@ -228,26 +248,26 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) bool ED_view3d_context_activate(bContext *C) { - bScreen *sc = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); + bScreen *screen = CTX_wm_screen(C); + ScrArea *area = CTX_wm_area(C); ARegion *region; - /* sa can be NULL when called from python */ - if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { - sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); + /* area can be NULL when called from python */ + if (area == NULL || area->spacetype != SPACE_VIEW3D) { + area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); } - if (sa == NULL) { + if (area == NULL) { return false; } - region = BKE_area_find_region_active_win(sa); + region = BKE_area_find_region_active_win(area); if (region == NULL) { return false; } /* bad context switch .. */ - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); return true; @@ -666,7 +686,7 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d, * Use with quad-split so each view is clipped by the bounds of each view axis. * \{ */ -static void view3d_boxview_clip(ScrArea *sa) +static void view3d_boxview_clip(ScrArea *area) { ARegion *region; BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); @@ -675,7 +695,7 @@ static void view3d_boxview_clip(ScrArea *sa) int val; /* create bounding box */ - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -747,7 +767,7 @@ static void view3d_boxview_clip(ScrArea *sa) } /* create bounding box */ - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -812,13 +832,13 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_ } /* sync center/zoom view of region to others, for view transforms */ -void view3d_boxview_sync(ScrArea *sa, ARegion *region) +void view3d_boxview_sync(ScrArea *area, ARegion *region) { ARegion *artest; RegionView3D *rv3d = region->regiondata; short clip = 0; - for (artest = sa->regionbase.first; artest; artest = artest->next) { + for (artest = area->regionbase.first; artest; artest = artest->next) { if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3dtest = artest->regiondata; @@ -833,18 +853,18 @@ void view3d_boxview_sync(ScrArea *sa, ARegion *region) } if (clip) { - view3d_boxview_clip(sa); + view3d_boxview_clip(area); } } /* for home, center etc */ -void view3d_boxview_copy(ScrArea *sa, ARegion *region) +void view3d_boxview_copy(ScrArea *area, ARegion *region) { ARegion *artest; RegionView3D *rv3d = region->regiondata; bool clip = false; - for (artest = sa->regionbase.first; artest; artest = artest->next) { + for (artest = area->regionbase.first; artest; artest = artest->next) { if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3dtest = artest->regiondata; @@ -859,14 +879,14 @@ void view3d_boxview_copy(ScrArea *sa, ARegion *region) } if (clip) { - view3d_boxview_clip(sa); + view3d_boxview_clip(area); } } /* 'clip' is used to know if our clip setting has changed */ -void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip) +void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) { - ARegion *ar_sync = NULL; + ARegion *region_sync = NULL; RegionView3D *rv3d = region->regiondata; short viewlock; /* this function copies flags from the first of the 3 other quadview @@ -892,21 +912,21 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip) rv3d->rflag &= ~RV3D_BOXCLIP; } - /* use ar_sync so we sync with one of the aligned views below + /* use region_sync so we sync with one of the aligned views below * else the view jumps on changing view settings like 'clip' * since it copies from the perspective view */ - ar_sync = region; + region_sync = region; } } if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); + view3d_boxview_sync(area, region_sync ? region_sync : area->regionbase.last); } /* ensure locked regions have an axis, locked user views don't make much sense */ if (viewlock & RV3D_LOCK_ROTATION) { int index_qsplit = 0; - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region->alignment == RGN_ALIGN_QSPLIT) { rv3d = region->regiondata; if (rv3d->viewlock) { @@ -922,7 +942,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip) } } - ED_area_tag_redraw(sa); + ED_area_tag_redraw(area); } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 30587e6084d..fe77ca05a04 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -128,7 +128,7 @@ void ED_view3d_smooth_view_ex( const Depsgraph *depsgraph, wmWindowManager *wm, wmWindow *win, - ScrArea *sa, + ScrArea *area, View3D *v3d, ARegion *region, const int smooth_viewtx, @@ -293,7 +293,7 @@ void ED_view3d_smooth_view_ex( } if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_copy(sa, region); + view3d_boxview_copy(area, region); } ED_region_tag_redraw(region); @@ -309,9 +309,9 @@ void ED_view3d_smooth_view(bContext *C, const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); - ED_view3d_smooth_view_ex(depsgraph, wm, win, sa, v3d, region, smooth_viewtx, sview); + ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview); } /* only meant for timer usage */ @@ -615,17 +615,18 @@ static void sync_viewport_camera_smoothview(bContext *C, if (v3d->scenelock) { ListBase *lb = (space_link == area->spacedata.first) ? &area->regionbase : &space_link->regionbase; - for (ARegion *other_ar = lb->first; other_ar != NULL; other_ar = other_ar->next) { - if (other_ar->regiontype == RGN_TYPE_WINDOW) { - if (other_ar->regiondata) { - RegionView3D *other_rv3d = other_ar->regiondata; + for (ARegion *other_region = lb->first; other_region != NULL; + other_region = other_region->next) { + if (other_region->regiontype == RGN_TYPE_WINDOW) { + if (other_region->regiondata) { + RegionView3D *other_rv3d = other_region->regiondata; if (other_rv3d->persp == RV3D_CAMOB) { Object *other_camera_old = other_v3d->camera; other_v3d->camera = ob; ED_view3d_lastview_store(other_rv3d); ED_view3d_smooth_view(C, other_v3d, - other_ar, + other_region, smooth_viewtx, &(const V3D_SmoothParams){ .camera_old = other_camera_old, @@ -704,9 +705,9 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) bool ED_operator_rv3d_user_region_poll(bContext *C) { View3D *v3d_dummy; - ARegion *ar_dummy; + ARegion *region_dummy; - return ED_view3d_context_user_region(C, &v3d_dummy, &ar_dummy); + return ED_view3d_context_user_region(C, &v3d_dummy, ®ion_dummy); } void VIEW3D_OT_object_as_camera(wmOperatorType *ot) @@ -1061,7 +1062,7 @@ int view3d_opengl_select(ViewContext *vc, * the number of items is nearly always 1, maybe 2..3 in rare cases. */ LinkNode *ob_pose_list = NULL; VirtualModifierData virtualModifierData; - const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData); + const ModifierData *md = BKE_modifiers_get_virtual_modifierlist(obact, &virtualModifierData); for (; md; md = md->next) { if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; @@ -1199,16 +1200,16 @@ finally: static uint free_localview_bit(Main *bmain) { - ScrArea *sa; - bScreen *sc; + ScrArea *area; + bScreen *screen; ushort local_view_bits = 0; /* sometimes we loose a localview: when an area is closed */ /* check all areas: which localviews are in use? */ - for (sc = bmain->screens.first; sc; sc = sc->id.next) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl = sa->spacedata.first; + for (screen = bmain->screens.first; screen; screen = screen->id.next) { + for (area = screen->areabase.first; area; area = area->next) { + SpaceLink *sl = area->spacedata.first; for (; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; @@ -1234,12 +1235,12 @@ static bool view3d_localview_init(const Depsgraph *depsgraph, wmWindow *win, Main *bmain, ViewLayer *view_layer, - ScrArea *sa, + ScrArea *area, const bool frame_selected, const int smooth_viewtx, ReportList *reports) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; Base *base; float min[3], max[3], box[3]; float size = 0.0f; @@ -1301,7 +1302,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph, memcpy(v3d->localvd, v3d, sizeof(View3D)); v3d->local_view_uuid = local_view_bit; - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; bool ok_dist = true; @@ -1342,7 +1343,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph, ED_view3d_smooth_view_ex(depsgraph, wm, win, - sa, + area, v3d, region, smooth_viewtx, @@ -1364,11 +1365,11 @@ static void view3d_localview_exit(const Depsgraph *depsgraph, wmWindowManager *wm, wmWindow *win, ViewLayer *view_layer, - ScrArea *sa, + ScrArea *area, const bool frame_selected, const int smooth_viewtx) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; if (v3d->localvd == NULL) { return; @@ -1389,7 +1390,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph, MEM_freeN(v3d->localvd); v3d->localvd = NULL; - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -1410,7 +1411,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph, ED_view3d_smooth_view_ex(depsgraph, wm, win, - sa, + area, v3d, region, smooth_viewtx, @@ -1438,23 +1439,23 @@ static int localview_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); View3D *v3d = CTX_wm_view3d(C); bool frame_selected = RNA_boolean_get(op->ptr, "frame_selected"); bool changed; if (v3d->localvd) { - view3d_localview_exit(depsgraph, wm, win, view_layer, sa, frame_selected, smooth_viewtx); + view3d_localview_exit(depsgraph, wm, win, view_layer, area, frame_selected, smooth_viewtx); changed = true; } else { changed = view3d_localview_init( - depsgraph, wm, win, bmain, view_layer, sa, frame_selected, smooth_viewtx, op->reports); + depsgraph, wm, win, bmain, view_layer, area, frame_selected, smooth_viewtx, op->reports); } if (changed) { DEG_id_type_tag(bmain, ID_OB); - ED_area_tag_redraw(sa); + ED_area_tag_redraw(area); /* Unselected objects become selected when exiting. */ if (v3d->localvd == NULL) { @@ -1555,19 +1556,17 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot) /** \name Local Collections * \{ */ -static uint free_localcollection_bit(Main *bmain, - unsigned short local_collections_uuid, - bool *r_reset) +static uint free_localcollection_bit(Main *bmain, ushort local_collections_uuid, bool *r_reset) { - ScrArea *sa; - bScreen *sc; + ScrArea *area; + bScreen *screen; ushort local_view_bits = 0; /* Check all areas: which localviews are in use? */ - for (sc = bmain->screens.first; sc; sc = sc->id.next) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl = sa->spacedata.first; + for (screen = bmain->screens.first; screen; screen = screen->id.next) { + for (area = screen->areabase.first; area; area = area->next) { + SpaceLink *sl = area->spacedata.first; for (; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; @@ -1596,7 +1595,7 @@ static uint free_localcollection_bit(Main *bmain, } static void local_collections_reset_uuid(LayerCollection *layer_collection, - const unsigned short local_view_bit) + const ushort local_view_bit) { if (layer_collection->flag & LAYER_COLLECTION_HIDE) { layer_collection->local_collections_bits &= ~local_view_bit; diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 89b5618075a..7aefd173953 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -160,14 +160,14 @@ void walk_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Walk Modal"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Walk Modal"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Walk Modal", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk"); @@ -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, |