From 69d6222481b4342dc2a153e62752145aa37ea101 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 18 Oct 2021 00:32:23 -0300 Subject: Snap and Placement Gizmo Refactor Move most of the gizmo snap and placement code to `view_cursor_snap.c`. Simplify and extend the snap API. Differential Revision: https://developer.blender.org/D12868 --- .../gizmo_library/gizmo_types/snap3d_gizmo.c | 589 +++---------- source/blender/editors/include/ED_gizmo_library.h | 41 +- .../include/ED_transform_snap_object_context.h | 3 +- source/blender/editors/include/ED_view3d.h | 68 ++ source/blender/editors/space_view3d/CMakeLists.txt | 1 + source/blender/editors/space_view3d/space_view3d.c | 4 + .../editors/space_view3d/view3d_cursor_snap.c | 954 +++++++++++++++++++++ source/blender/editors/space_view3d/view3d_edit.c | 3 +- .../editors/space_view3d/view3d_gizmo_ruler.c | 20 +- .../editors/space_view3d/view3d_placement.c | 854 +++--------------- source/blender/editors/transform/transform_snap.c | 10 +- .../editors/transform/transform_snap_object.c | 47 +- 12 files changed, 1290 insertions(+), 1304 deletions(-) create mode 100644 source/blender/editors/space_view3d/view3d_cursor_snap.c (limited to 'source/blender/editors') diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index 322ae87befa..fccb65bad68 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -27,420 +27,122 @@ * \brief Snap gizmo which exposes the location, normal and index in the props. */ +#include "MEM_guardedalloc.h" + #include "BLI_listbase.h" #include "BLI_math.h" -#include "DNA_scene_types.h" - #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" -#include "GPU_immediate.h" -#include "GPU_state.h" - #include "ED_gizmo_library.h" #include "ED_screen.h" #include "ED_transform_snap_object_context.h" #include "ED_view3d.h" -#include "UI_resources.h" /* icons */ +#include "UI_resources.h" #include "RNA_access.h" #include "RNA_define.h" -#include "DEG_depsgraph_query.h" - #include "WM_api.h" -#include "WM_types.h" /* own includes */ -#include "../gizmo_geometry.h" #include "../gizmo_library_intern.h" typedef struct SnapGizmo3D { wmGizmo gizmo; - - /* We could have other snap contexts, for now only support 3D view. */ - SnapObjectContext *snap_context_v3d; - - /* Copy of the parameters of the last event state in order to detect updates. */ - struct { - int x; - int y; -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK - short shift, ctrl, alt, oskey; -#endif - } last_eventstate; - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK - wmKeyMap *keymap; - int snap_on; - bool invert_snap; -#endif - - /* Setup. */ - eSnapGizmo flag; - float *prevpoint; - float prevpoint_stack[3]; - short snap_elem_force; - - /* Return values. */ - short snap_elem; - float loc[3]; - float nor[3]; - int elem_index[3]; - - /** Enabled when snap is activated, even if it didn't find anything. */ - bool is_enabled; + V3DSnapCursorData *cursor_handle; } SnapGizmo3D; -/* Checks if the current event is different from the one captured in the last update. */ -static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) +static void snap_gizmo_snap_elements_update(SnapGizmo3D *snap_gizmo) { - if (wm && wm->winactive) { - const wmEvent *event = wm->winactive->eventstate; - if ((event->x != snap_gizmo->last_eventstate.x) || - (event->y != snap_gizmo->last_eventstate.y)) { - return true; - } -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK - if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) { - if ((event->ctrl != snap_gizmo->last_eventstate.ctrl) || - (event->shift != snap_gizmo->last_eventstate.shift) || - (event->alt != snap_gizmo->last_eventstate.alt) || - (event->oskey != snap_gizmo->last_eventstate.oskey)) { - return true; - } - } -#endif - } - return false; -} + V3DSnapCursorData *snap_data = snap_gizmo->cursor_handle; + wmGizmoProperty *gz_prop_snap; + gz_prop_snap = WM_gizmo_target_property_find(&snap_gizmo->gizmo, "snap_elements"); -/* Copies the current eventstate. */ -static void eventstate_save_xy(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) -{ - if (wm && wm->winactive) { - const wmEvent *event = wm->winactive->eventstate; - snap_gizmo->last_eventstate.x = event->x; - snap_gizmo->last_eventstate.y = event->y; - } -} - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK -static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) -{ - if (!wm || !wm->winactive) { - return false; - } - - const wmEvent *event = wm->winactive->eventstate; - if ((event->ctrl == snap_gizmo->last_eventstate.ctrl) && - (event->shift == snap_gizmo->last_eventstate.shift) && - (event->alt == snap_gizmo->last_eventstate.alt) && - (event->oskey == snap_gizmo->last_eventstate.oskey)) { - /* Nothing has changed. */ - return snap_gizmo->invert_snap; - } - - /* Save new eventstate. */ - snap_gizmo->last_eventstate.ctrl = event->ctrl; - snap_gizmo->last_eventstate.shift = event->shift; - snap_gizmo->last_eventstate.alt = event->alt; - snap_gizmo->last_eventstate.oskey = event->oskey; - - const int snap_on = snap_gizmo->snap_on; - - wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { - if (kmi->flag & KMI_INACTIVE) { - continue; - } - - if (kmi->propvalue == snap_on) { - if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || - (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || - (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || - ((kmi->type == EVT_OSKEY) && event->oskey)) { - return true; - } - } + if (gz_prop_snap->prop) { + snap_data->snap_elem_force |= RNA_property_enum_get(&gz_prop_snap->ptr, gz_prop_snap->prop); } - return false; -} -#endif - -static short snap_gizmo_snap_elements(SnapGizmo3D *snap_gizmo) -{ - int snap_elements = snap_gizmo->snap_elem_force; - wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(&snap_gizmo->gizmo, "snap_elements"); - if (gz_prop->prop) { - snap_elements |= RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); - } - snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR); - return (ushort)snap_elements; + UI_GetThemeColor3ubv(TH_TRANSFORM, snap_data->color_line); + snap_data->color_line[3] = 128; + rgba_float_to_uchar(snap_data->color_point, snap_gizmo->gizmo.color); } /* -------------------------------------------------------------------- */ /** \name ED_gizmo_library specific API * \{ */ -void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d, - const float loc_prev[3], - const float loc_curr[3], - const float normal[3], - const uchar color_line[4], - const uchar color_point[4], - const short snap_elem_type) +SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, wmGizmo *UNUSED(gz)) { - if (!loc_prev && !loc_curr) { - return; - } - - float view_inv[4][4]; - copy_m4_m4(view_inv, rv3d->viewinv); - - /* The size of the circle is larger than the vertex size. - * This prevents a drawing overlaps the other. */ - float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (loc_curr) { - immUniformColor4ubv(color_point); - imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos); - - /* draw normal if needed */ - if (normal) { - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, loc_curr); - immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]); - immEnd(); - } - } - - if (loc_prev) { - /* Draw an "X" indicating where the previous snap point is. - * This is useful for indicating perpendicular snap. */ - - /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */ - float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; - - /* Multiply by 0.75f so that the final size of the "X" is close to that of - * the circle. - * (A closer value is 0.7071f, but we don't need to be exact here). */ - float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev); - - mul_v3_v3fl(vx, view_inv[0], x_size); - mul_v3_v3fl(vy, view_inv[1], x_size); - - add_v3_v3v3(v1, vx, vy); - sub_v3_v3v3(v2, vx, vy); - negate_v3_v3(v3, v1); - negate_v3_v3(v4, v2); - - add_v3_v3(v1, loc_prev); - add_v3_v3(v2, loc_prev); - add_v3_v3(v3, loc_prev); - add_v3_v3(v4, loc_prev); - - immUniformColor4ubv(color_line); - immBegin(GPU_PRIM_LINES, 4); - immVertex3fv(pos, v3); - immVertex3fv(pos, v1); - immVertex3fv(pos, v4); - immVertex3fv(pos, v2); - immEnd(); - - if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { - /* Dashed line. */ - immUnbindProgram(); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - immUniform1f("dash_width", 6.0f * U.pixelsize); - immUniform1f("dash_factor", 1.0f / 4.0f); - immUniformColor4ubv(color_line); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, loc_prev); - immVertex3fv(pos, loc_curr); - immEnd(); - } - } - - immUnbindProgram(); -} - -SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, wmGizmo *gz) -{ - SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - if (snap_gizmo->snap_context_v3d == NULL) { - snap_gizmo->snap_context_v3d = ED_transform_snap_object_context_create(scene, 0); - } - return snap_gizmo->snap_context_v3d; + ED_view3d_cursor_snap_activate_point(); + return ED_view3d_cursor_snap_context_ensure(scene); } -void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag) +void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, int flag) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - snap_gizmo->flag |= flag; + snap_gizmo->cursor_handle->flag |= flag; } -void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, eSnapGizmo flag) +void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, int flag) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - snap_gizmo->flag &= ~flag; + snap_gizmo->cursor_handle->flag &= ~flag; } -bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, eSnapGizmo flag) +bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, int flag) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - return (snap_gizmo->flag & flag) != 0; + return (snap_gizmo->cursor_handle->flag & flag) != 0; } bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz) { -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - return snap_gizmo->invert_snap; -#else - return false; -#endif + return snap_gizmo->cursor_handle->is_snap_invert; } bool ED_gizmotypes_snap_3d_is_enabled(const wmGizmo *gz) { const SnapGizmo3D *snap_gizmo = (const SnapGizmo3D *)gz; - return snap_gizmo->is_enabled; + return snap_gizmo->cursor_handle->is_enabled; } -short ED_gizmotypes_snap_3d_update(wmGizmo *gz, - struct Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - const wmWindowManager *wm, - const float mval_fl[2]) +void ED_gizmotypes_snap_3d_data_get(const struct bContext *C, + wmGizmo *gz, + float r_loc[3], + float r_nor[3], + int r_elem_index[3], + int *r_snap_elem) { - SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - snap_gizmo->is_enabled = false; - - Scene *scene = DEG_get_input_scene(depsgraph); - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK - if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) { - snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm); - - const ToolSettings *ts = scene->toolsettings; - if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) { - snap_gizmo->snap_elem = 0; - return 0; - } - } -#endif - eventstate_save_xy(snap_gizmo, wm); - - snap_gizmo->is_enabled = true; - - float co[3], no[3]; - short snap_elem = 0; - int snap_elem_index[3] = {-1, -1, -1}; - int index = -1; - - ushort snap_elements = snap_gizmo_snap_elements(snap_gizmo); - - if (snap_elements) { - float prev_co[3] = {0.0f}; - if (snap_gizmo->prevpoint) { - copy_v3_v3(prev_co, snap_gizmo->prevpoint); + V3DSnapCursorData *snap_data = ((SnapGizmo3D *)gz)->cursor_handle; + + if (C) { + /* Snap values are updated too late at the cursor. Be sure to update ahead of time. */ + wmWindowManager *wm = CTX_wm_manager(C); + const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL; + if (event) { + ARegion *region = CTX_wm_region(C); + int x = event->x - region->winrct.xmin; + int y = event->y - region->winrct.ymin; + ED_view3d_cursor_snap_update(C, x, y, snap_data); } - else { - snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; - } - - eSnapSelect snap_select = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_ONLY_ACTIVE) ? - SNAP_ONLY_ACTIVE : - SNAP_ALL; - - eSnapEditType edit_mode_type = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL) ? - SNAP_GEOM_FINAL : - (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE) ? - SNAP_GEOM_CAGE : - SNAP_GEOM_EDIT; - - bool use_occlusion_test = (snap_gizmo->flag & ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE) ? false : - true; - - float dist_px = 12.0f * U.pixelsize; - - ED_gizmotypes_snap_3d_context_ensure(scene, gz); - snap_elem = ED_transform_snap_object_project_view3d_ex( - snap_gizmo->snap_context_v3d, - depsgraph, - region, - v3d, - snap_elements, - &(const struct SnapObjectParams){ - .snap_select = snap_select, - .edit_mode_type = edit_mode_type, - .use_occlusion_test = use_occlusion_test, - }, - mval_fl, - prev_co, - &dist_px, - co, - no, - &index, - NULL, - NULL); } - if (snap_elem == 0) { - RegionView3D *rv3d = region->regiondata; - ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co); - zero_v3(no); - } - else if (snap_elem == SCE_SNAP_MODE_VERTEX) { - snap_elem_index[0] = index; - } - else if (snap_elem & - (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { - snap_elem_index[1] = index; - } - else if (snap_elem == SCE_SNAP_MODE_FACE) { - snap_elem_index[2] = index; - } - - snap_gizmo->snap_elem = snap_elem; - copy_v3_v3(snap_gizmo->loc, co); - copy_v3_v3(snap_gizmo->nor, no); - copy_v3_v3_int(snap_gizmo->elem_index, snap_elem_index); - - return snap_elem; -} - -void ED_gizmotypes_snap_3d_data_get( - wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem) -{ - SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - BLI_assert(snap_gizmo->is_enabled); if (r_loc) { - copy_v3_v3(r_loc, snap_gizmo->loc); + copy_v3_v3(r_loc, snap_data->loc); } if (r_nor) { - copy_v3_v3(r_nor, snap_gizmo->nor); + copy_v3_v3(r_nor, snap_data->nor); } if (r_elem_index) { - copy_v3_v3_int(r_elem_index, snap_gizmo->elem_index); + copy_v3_v3_int(r_elem_index, snap_data->elem_index); } if (r_snap_elem) { - *r_snap_elem = snap_gizmo->snap_elem; + *r_snap_elem = snap_data->snap_elem; } } @@ -450,115 +152,80 @@ void ED_gizmotypes_snap_3d_data_get( /** \name RNA callbacks * \{ */ -/* Based on 'rna_GizmoProperties_find_operator'. */ -static struct SnapGizmo3D *gizmo_snap_rna_find_operator(PointerRNA *ptr) -{ - IDProperty *properties = ptr->data; - for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) { - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - if (area->spacetype != SPACE_VIEW3D) { - continue; - } - LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->regiontype == RGN_TYPE_WINDOW && region->gizmo_map) { - wmGizmoMap *gzmap = region->gizmo_map; - LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) { - LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { - if (gz->properties == properties) { - return (SnapGizmo3D *)gz; - } - } - } - } - } - } - } - return NULL; -} - -static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *ptr, +static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop)) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - return snap_gizmo->snap_elem_force; + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + return snap_data->snap_elem_force; } return 0; } -static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), int value) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - snap_gizmo->snap_elem_force = (short)value; + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + snap_data->snap_elem_force = (short)value; } } -static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), float *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - copy_v3_v3(values, snap_gizmo->prevpoint_stack); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data && snap_data->prevpoint) { + copy_v3_v3(values, snap_data->prevpoint); } } -static void gizmo_snap_rna_prevpoint_set_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_prevpoint_set_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), const float *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - if (values) { - copy_v3_v3(snap_gizmo->prevpoint_stack, values); - snap_gizmo->prevpoint = snap_gizmo->prevpoint_stack; - } - else { - snap_gizmo->prevpoint = NULL; - } - } + ED_view3d_cursor_snap_prevpoint_set(values); } -static void gizmo_snap_rna_location_get_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_location_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), float *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - copy_v3_v3(values, snap_gizmo->loc); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + copy_v3_v3(values, snap_data->loc); } } -static void gizmo_snap_rna_location_set_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_location_set_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), const float *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - copy_v3_v3(snap_gizmo->loc, values); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + copy_v3_v3(snap_data->loc, values); } } -static void gizmo_snap_rna_normal_get_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_normal_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), float *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - copy_v3_v3(values, snap_gizmo->nor); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + copy_v3_v3(values, snap_data->nor); } } -static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr, +static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), int *values) { - SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); - if (snap_gizmo) { - copy_v3_v3_int(values, snap_gizmo->elem_index); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (snap_data) { + copy_v3_v3_int(values, snap_data->elem_index); } } @@ -571,91 +238,44 @@ static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr, static void snap_gizmo_setup(wmGizmo *gz) { gz->flag |= WM_GIZMO_NO_TOOLTIP; - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - wmKeyConfig *keyconf = gz->parent_gzgroup->type->keyconf; - if (!keyconf) { - /* It can happen when gizmo-group-type is not linked at startup. */ - keyconf = ((wmWindowManager *)G.main->wm.first)->defaultconf; - } - snap_gizmo->keymap = WM_modalkeymap_find(keyconf, "Generic Gizmo Tweak Modal Map"); - RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on); -#endif + ED_view3d_cursor_snap_activate_point(); + snap_gizmo->cursor_handle = ED_view3d_cursor_snap_data_get(); } -static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) +static void snap_gizmo_draw(const bContext *UNUSED(C), wmGizmo *UNUSED(gz)) { - SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - if (snap_gizmo->snap_elem == 0) { - return; - } - - wmWindowManager *wm = CTX_wm_manager(C); - if (eventstate_has_changed(snap_gizmo, wm)) { - /* The eventstate has changed but the snap has not been updated. - * This means that the current position is no longer valid. */ - snap_gizmo->snap_elem = 0; - return; - } - - RegionView3D *rv3d = CTX_wm_region_data(C); - if (rv3d->rflag & RV3D_NAVIGATING) { - /* Don't draw the gizmo while navigating. It can be distracting. */ - snap_gizmo->snap_elem = 0; - return; - } - - uchar color_line[4], color_point[4]; - UI_GetThemeColor3ubv(TH_TRANSFORM, color_line); - color_line[3] = 128; - - rgba_float_to_uchar(color_point, gz->color); - - GPU_line_smooth(false); - - GPU_line_width(1.0f); - - const float *prev_point = (snap_gizmo_snap_elements(snap_gizmo) & - SCE_SNAP_MODE_EDGE_PERPENDICULAR) ? - snap_gizmo->prevpoint : - NULL; - - ED_gizmotypes_snap_3d_draw_util( - rv3d, prev_point, snap_gizmo->loc, NULL, color_line, color_point, snap_gizmo->snap_elem); + /* All drawing is handled at the paint cursor. */ } static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - wmWindowManager *wm = CTX_wm_manager(C); - ARegion *region = CTX_wm_region(C); - - /* FIXME: this hack is to ignore drag events, otherwise drag events - * cause momentary snap gizmo re-positioning at the drag-start location, see: T87511. */ - if (wm && wm->winactive) { - const wmEvent *event = wm->winactive->eventstate; - int mval_compare[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin}; - if (!equals_v2v2_int(mval_compare, mval)) { - return snap_gizmo->snap_elem ? 0 : -1; - } - } + V3DSnapCursorData *snap_data = snap_gizmo->cursor_handle; - if (!eventstate_has_changed(snap_gizmo, wm)) { - /* Performance, do not update. */ - return snap_gizmo->snap_elem ? 0 : -1; - } + /* Snap Elements can change while the gizmo is active. Need to be updated somewhere. */ + snap_gizmo_snap_elements_update(snap_gizmo); - View3D *v3d = CTX_wm_view3d(C); - const float mval_fl[2] = {UNPACK2(mval)}; - short snap_elem = ED_gizmotypes_snap_3d_update( - gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl); + /* Snap values are updated too late at the cursor. Be sure to update ahead of time. */ + int x, y; + { + wmWindowManager *wm = CTX_wm_manager(C); + const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL; + if (event) { + ARegion *region = CTX_wm_region(C); + x = event->x - region->winrct.xmin; + y = event->y - region->winrct.ymin; + } + else { + x = mval[0]; + y = mval[1]; + } + } + ED_view3d_cursor_snap_update(C, x, y, snap_data); - if (snap_elem) { - ED_region_tag_redraw_editor_overlays(region); + if (snap_data && snap_data->snap_elem) { return 0; } - return -1; } @@ -677,9 +297,9 @@ static int snap_gizmo_invoke(bContext *UNUSED(C), static void snap_gizmo_free(wmGizmo *gz) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - if (snap_gizmo->snap_context_v3d) { - ED_transform_snap_object_context_destroy(snap_gizmo->snap_context_v3d); - snap_gizmo->snap_context_v3d = NULL; + V3DSnapCursorData *snap_data = snap_gizmo->cursor_handle; + if (snap_data) { + ED_view3d_cursor_snap_deactivate_point(); } } @@ -719,7 +339,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE, "Snap Elements", ""); - RNA_def_property_enum_funcs_runtime(prop, gizmo_snap_rna_snap_elements_force_get_fn, gizmo_snap_rna_snap_elements_force_set_fn, @@ -735,7 +354,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) "Point that defines the location of the perpendicular snap", FLT_MIN, FLT_MAX); - RNA_def_property_float_array_funcs_runtime( prop, gizmo_snap_rna_prevpoint_get_fn, gizmo_snap_rna_prevpoint_set_fn, NULL); @@ -750,7 +368,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) "Snap Point Location", FLT_MIN, FLT_MAX); - RNA_def_property_float_array_funcs_runtime( prop, gizmo_snap_rna_location_get_fn, gizmo_snap_rna_location_set_fn, NULL); @@ -764,7 +381,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) "Snap Point Normal", FLT_MIN, FLT_MAX); - RNA_def_property_float_array_funcs_runtime(prop, gizmo_snap_rna_normal_get_fn, NULL, NULL); prop = RNA_def_int_vector(gzt->srna, @@ -777,7 +393,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) "Array index of face, edge and vert snapped", INT_MIN, INT_MAX); - RNA_def_property_int_array_funcs_runtime( prop, gizmo_snap_rna_snap_elem_index_get_fn, NULL, NULL); diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 9bef5a17d12..4d922162ee9 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -41,11 +41,7 @@ void ED_gizmotypes_primitive_3d(void); void ED_gizmotypes_blank_3d(void); void ED_gizmotypes_snap_3d(void); -struct ARegion; -struct Depsgraph; struct Object; -struct SnapObjectContext; -struct View3D; struct bContext; struct wmGizmo; struct wmWindowManager; @@ -248,41 +244,22 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], struct Dial3dParams *params); /* snap3d_gizmo.c */ -#define USE_SNAP_DETECT_FROM_KEYMAP_HACK -void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d, - const float loc_prev[3], - const float loc_curr[3], - const float normal[3], - const uchar color_line[4], - const uchar color_point[4], - const short snap_elem_type); struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene, struct wmGizmo *gz); -typedef enum { - ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE = 1 << 0, - ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE = 1 << 1, - ED_SNAPGIZMO_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */ - ED_SNAPGIZMO_SNAP_ONLY_ACTIVE = 1 << 3, - ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL = 1 << 4, - ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE = 1 << 5, -} eSnapGizmo; - -void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag); -void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, eSnapGizmo flag); -bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, eSnapGizmo flag); +void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, int flag); +void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, int flag); +bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, int flag); bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz); bool ED_gizmotypes_snap_3d_is_enabled(const struct wmGizmo *gz); -short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz, - struct Depsgraph *depsgraph, - const struct ARegion *region, - const struct View3D *v3d, - const struct wmWindowManager *wm, - const float mval_fl[2]); -void ED_gizmotypes_snap_3d_data_get( - struct wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem); +void ED_gizmotypes_snap_3d_data_get(const struct bContext *C, + struct wmGizmo *gz, + float r_loc[3], + float r_nor[3], + int r_elem_index[3], + int *r_snap_elem); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 7311303d7cd..7002db163b6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -139,7 +139,8 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, float r_no[3], int *r_index, struct Object **r_ob, - float r_obmat[4][4]); + float r_obmat[4][4], + float r_face_nor[3]); bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index cf8dcbd7995..593d1be9444 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -52,6 +52,7 @@ struct RegionView3D; struct RenderEngineType; struct Scene; struct ScrArea; +struct SnapObjectContext; struct View3D; struct ViewContext; struct ViewLayer; @@ -228,6 +229,73 @@ typedef enum { (V3D_PROJ_TEST_CLIP_CONTENT | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_FAR | \ V3D_PROJ_TEST_CLIP_WIN) +/* view3d_cursor_snap.c */ +#define USE_SNAP_DETECT_FROM_KEYMAP_HACK +typedef enum { + V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE = 1 << 0, + V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE = 1 << 1, + V3D_SNAPCURSOR_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */ + V3D_SNAPCURSOR_SNAP_ONLY_ACTIVE = 1 << 3, + V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL = 1 << 4, + V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE = 1 << 5, +} eV3DSnapCursor; + +typedef enum { + V3D_PLACE_DEPTH_SURFACE = 0, + V3D_PLACE_DEPTH_CURSOR_PLANE = 1, + V3D_PLACE_DEPTH_CURSOR_VIEW = 2, +} eV3DPlaceDepth; + +typedef enum { + V3D_PLACE_ORIENT_SURFACE = 0, + V3D_PLACE_ORIENT_DEFAULT = 1, +} eV3DPlaceOrient; + +typedef struct V3DSnapCursorData { + /* Setup. */ + eV3DSnapCursor flag; + eV3DPlaceDepth plane_depth; + eV3DPlaceOrient plane_orient; + uchar color_line[4]; + uchar color_point[4]; + float *prevpoint; + short snap_elem_force; /* If zero, use scene settings. */ + short plane_axis; + bool use_plane_axis_auto; + + /* Return values. */ + short snap_elem; + float loc[3]; + float nor[3]; + float face_nor[3]; + float obmat[4][4]; + int elem_index[3]; + float plane_omat[3][3]; + bool is_snap_invert; + + /** Enabled when snap is activated, even if it didn't find anything. */ + bool is_enabled; +} V3DSnapCursorData; + +V3DSnapCursorData *ED_view3d_cursor_snap_data_get(void); +void ED_view3d_cursor_snap_activate_point(void); +void ED_view3d_cursor_snap_activate_plane(void); +void ED_view3d_cursor_snap_deactivate_point(void); +void ED_view3d_cursor_snap_deactivate_plane(void); +void ED_view3d_cursor_snap_update(const struct bContext *C, + const int x, + const int y, + V3DSnapCursorData *snap_data); +void ED_view3d_cursor_snap_prevpoint_set(const float prev_point[3]); +struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene); +void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type); + /* view3d_iterators.c */ /* foreach iterators */ diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index fe84a3b8ae9..19f869ed50b 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC space_view3d.c view3d_buttons.c view3d_camera_control.c + view3d_cursor_snap.c view3d_draw.c view3d_edit.c view3d_gizmo_armature.c diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 787cf529483..83aa2d93fbb 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -355,6 +355,10 @@ static void view3d_exit(wmWindowManager *UNUSED(wm), ScrArea *area) BLI_assert(area->spacetype == SPACE_VIEW3D); View3D *v3d = area->spacedata.first; MEM_SAFE_FREE(v3d->runtime.local_stats); + + /* Be sure to release the #V3DSnapCursorData from the cursor, or it will get lost. */ + ED_view3d_cursor_snap_deactivate_point(); + ED_view3d_cursor_snap_deactivate_plane(); } static SpaceLink *view3d_duplicate(SpaceLink *sl) diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c new file mode 100644 index 00000000000..03aa9316a38 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -0,0 +1,954 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + * + * \brief Snap cursor. + */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_scene.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" + +#include "RNA_access.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" +#include "wm.h" + +typedef struct SnapCursorDataIntern { + /* Keep as first member. */ + struct V3DSnapCursorData snap_data; + + struct SnapObjectContext *snap_context_v3d; + float prevpoint_stack[3]; + short snap_elem_hidden; + + /* Copy of the parameters of the last event state in order to detect updates. */ + struct { + int x; + int y; +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + short shift, ctrl, alt, oskey; +#endif + } last_eventstate; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + struct wmKeyMap *keymap; + int snap_on; +#endif + + struct wmPaintCursor *handle; + + bool draw_point; + bool draw_plane; +} SnapCursorDataIntern; + +/** + * Calculate a 3x3 orientation matrix from the surface under the cursor. + */ +static void cursor_poject_surface_normal(const float normal[3], + const float obmat[4][4], + float r_mat[3][3]) +{ + float mat[3][3]; + copy_m3_m4(mat, obmat); + normalize_m3(mat); + + float dot_best = fabsf(dot_v3v3(mat[0], normal)); + int i_best = 0; + for (int i = 1; i < 3; i++) { + float dot_test = fabsf(dot_v3v3(mat[i], normal)); + if (dot_test > dot_best) { + i_best = i; + dot_best = dot_test; + } + } + if (dot_v3v3(mat[i_best], normal) < 0.0f) { + negate_v3(mat[(i_best + 1) % 3]); + negate_v3(mat[(i_best + 2) % 3]); + } + copy_v3_v3(mat[i_best], normal); + orthogonalize_m3(mat, i_best); + normalize_m3(mat); + + copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]); + copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]); + copy_v3_v3(r_mat[2], mat[i_best]); +} + +/** + * Calculate 3D view incremental (grid) snapping. + * + * \note This could be moved to a public function. + */ +static bool cursor_snap_calc_incremental( + Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3]) +{ + const float grid_size = ED_view3d_grid_view_scale(scene, v3d, region, NULL); + if (UNLIKELY(grid_size == 0.0f)) { + return false; + } + + if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) { + co_relative = NULL; + } + + if (co_relative != NULL) { + sub_v3_v3(co, co_relative); + } + mul_v3_fl(co, 1.0f / grid_size); + co[0] = roundf(co[0]); + co[1] = roundf(co[1]); + co[2] = roundf(co[2]); + mul_v3_fl(co, grid_size); + if (co_relative != NULL) { + add_v3_v3(co, co_relative); + } + + return true; +} + +/** + * Re-order \a mat so \a axis_align uses its own axis which is closest to \a v. + */ +static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3]) +{ + float dot_best = -1.0f; + int axis_found = axis_align; + for (int i = 0; i < 3; i++) { + const float dot_test = fabsf(dot_v3v3(mat[i], v)); + if (dot_test > dot_best) { + dot_best = dot_test; + axis_found = i; + } + } + + if (axis_align != axis_found) { + float tmat[3][3]; + copy_m3_m3(tmat, mat); + const int offset = mod_i(axis_found - axis_align, 3); + for (int i = 0; i < 3; i++) { + copy_v3_v3(mat[i], tmat[(i + offset) % 3]); + } + return true; + } + return false; +} + +/* -------------------------------------------------------------------- */ +/** \name Drawings + * \{ */ + +static void cursor_plane_draw_grid(const int resolution, + const float scale, + const float scale_fade, + const float matrix[4][4], + const int plane_axis, + const float color[4]) +{ + BLI_assert(scale_fade <= scale); + const int resolution_min = resolution - 1; + float color_fade[4] = {UNPACK4(color)}; + const float *center = matrix[3]; + + GPU_blend(GPU_BLEND_ADDITIVE); + GPU_line_smooth(true); + GPU_line_width(1.0f); + + GPUVertFormat *format = immVertexFormat(); + const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + const uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); + + const size_t coords_len = resolution * resolution; + float(*coords)[3] = MEM_mallocN(sizeof(*coords) * coords_len, __func__); + + const int axis_x = (plane_axis + 0) % 3; + const int axis_y = (plane_axis + 1) % 3; + const int axis_z = (plane_axis + 2) % 3; + + int i; + const float resolution_div = (float)1.0f / (float)resolution; + i = 0; + for (int x = 0; x < resolution; x++) { + const float x_fl = (x * resolution_div) - 0.5f; + for (int y = 0; y < resolution; y++) { + const float y_fl = (y * resolution_div) - 0.5f; + coords[i][axis_x] = 0.0f; + coords[i][axis_y] = x_fl * scale; + coords[i][axis_z] = y_fl * scale; + mul_m4_v3(matrix, coords[i]); + i += 1; + } + } + BLI_assert(i == coords_len); + immBeginAtMost(GPU_PRIM_LINES, coords_len * 4); + i = 0; + for (int x = 0; x < resolution_min; x++) { + for (int y = 0; y < resolution_min; y++) { + + /* Add #resolution_div to ensure we fade-out entirely. */ +#define FADE(v) \ + max_ff(0.0f, (1.0f - square_f(((len_v3v3(v, center) / scale_fade) + resolution_div) * 2.0f))) + + const float *v0 = coords[(resolution * x) + y]; + const float *v1 = coords[(resolution * (x + 1)) + y]; + const float *v2 = coords[(resolution * x) + (y + 1)]; + + const float f0 = FADE(v0); + const float f1 = FADE(v1); + const float f2 = FADE(v2); + + if (f0 > 0.0f || f1 > 0.0f) { + color_fade[3] = color[3] * f0; + immAttr4fv(col_id, color_fade); + immVertex3fv(pos_id, v0); + color_fade[3] = color[3] * f1; + immAttr4fv(col_id, color_fade); + immVertex3fv(pos_id, v1); + } + if (f0 > 0.0f || f2 > 0.0f) { + color_fade[3] = color[3] * f0; + immAttr4fv(col_id, color_fade); + immVertex3fv(pos_id, v0); + + color_fade[3] = color[3] * f2; + immAttr4fv(col_id, color_fade); + immVertex3fv(pos_id, v2); + } + +#undef FADE + + i++; + } + } + + MEM_freeN(coords); + + immEnd(); + + immUnbindProgram(); + + GPU_line_smooth(false); + GPU_blend(GPU_BLEND_NONE); +} + +static void cursor_plane_draw(const RegionView3D *rv3d, + const int plane_axis, + const float matrix[4][4]) +{ + /* Draw */ + float pixel_size; + + if (rv3d->is_persp) { + float center[3]; + negate_v3_v3(center, rv3d->ofs); + pixel_size = ED_view3d_pixel_size(rv3d, center); + } + else { + pixel_size = ED_view3d_pixel_size(rv3d, matrix[3]); + } + + if (pixel_size > FLT_EPSILON) { + + /* Arbitrary, 1.0 is a little too strong though. */ + float color_alpha = 0.75f; + if (rv3d->is_persp) { + /* Scale down the alpha when this is drawn very small, + * since the add shader causes the small size to show too dense & bright. */ + const float relative_pixel_scale = pixel_size / ED_view3d_pixel_size(rv3d, matrix[3]); + if (relative_pixel_scale < 1.0f) { + color_alpha *= max_ff(square_f(relative_pixel_scale), 0.3f); + } + } + + { + /* Extra adjustment when it's near view-aligned as it seems overly bright. */ + float view_vector[3]; + ED_view3d_global_to_vector(rv3d, matrix[3], view_vector); + float view_dot = fabsf(dot_v3v3(matrix[plane_axis], view_vector)); + color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot))); + } + + const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize; + + float final_scale = (scale_mod * pixel_size); + + const int lines_subdiv = 10; + int lines = lines_subdiv; + + float final_scale_fade = final_scale; + final_scale = ceil_power_of_10(final_scale); + + float fac = final_scale_fade / final_scale; + + float color[4] = {1, 1, 1, color_alpha}; + color[3] *= square_f(1.0f - fac); + if (color[3] > 0.0f) { + cursor_plane_draw_grid( + lines * lines_subdiv, final_scale, final_scale_fade, matrix, plane_axis, color); + } + + color[3] = color_alpha; + /* When the grid is large, we only need the 2x lines in the middle. */ + if (fac < 0.2f) { + lines = 1; + final_scale = final_scale_fade; + } + cursor_plane_draw_grid(lines, final_scale, final_scale_fade, matrix, plane_axis, color); + } +} + +void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type) +{ + if (!loc_prev && !loc_curr) { + return; + } + + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); + + /* The size of the circle is larger than the vertex size. + * This prevents a drawing overlaps the other. */ + float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (loc_curr) { + immUniformColor4ubv(color_point); + imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos); + + /* draw normal if needed */ + if (normal) { + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_curr); + immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]); + immEnd(); + } + } + + if (loc_prev) { + /* Draw an "X" indicating where the previous snap point is. + * This is useful for indicating perpendicular snap. */ + + /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */ + float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; + + /* Multiply by 0.75f so that the final size of the "X" is close to that of + * the circle. + * (A closer value is 0.7071f, but we don't need to be exact here). */ + float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev); + + mul_v3_v3fl(vx, view_inv[0], x_size); + mul_v3_v3fl(vy, view_inv[1], x_size); + + add_v3_v3v3(v1, vx, vy); + sub_v3_v3v3(v2, vx, vy); + negate_v3_v3(v3, v1); + negate_v3_v3(v4, v2); + + add_v3_v3(v1, loc_prev); + add_v3_v3(v2, loc_prev); + add_v3_v3(v3, loc_prev); + add_v3_v3(v4, loc_prev); + + immUniformColor4ubv(color_line); + immBegin(GPU_PRIM_LINES, 4); + immVertex3fv(pos, v3); + immVertex3fv(pos, v1); + immVertex3fv(pos, v4); + immVertex3fv(pos, v2); + immEnd(); + + if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + /* Dashed line. */ + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + immUniform1f("dash_width", 6.0f * U.pixelsize); + immUniform1f("dash_factor", 1.0f / 4.0f); + immUniformColor4ubv(color_line); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_prev); + immVertex3fv(pos, loc_curr); + immEnd(); + } + } + + immUnbindProgram(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event State + * \{ */ + +/* Checks if the current event is different from the one captured in the last update. */ +static bool eventstate_has_changed(SnapCursorDataIntern *sdata_intern, + const wmWindowManager *wm, + const int x, + const int y) +{ + V3DSnapCursorData *snap_data = (V3DSnapCursorData *)sdata_intern; + if (wm && wm->winactive) { + const wmEvent *event = wm->winactive->eventstate; + if ((x != sdata_intern->last_eventstate.x) || (y != sdata_intern->last_eventstate.y)) { + return true; + } +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (!(snap_data && (snap_data->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE))) { + if ((event->ctrl != sdata_intern->last_eventstate.ctrl) || + (event->shift != sdata_intern->last_eventstate.shift) || + (event->alt != sdata_intern->last_eventstate.alt) || + (event->oskey != sdata_intern->last_eventstate.oskey)) { + return true; + } + } +#endif + } + return false; +} + +/* Copies the current eventstate. */ +static void eventstate_save_xy(SnapCursorDataIntern *cursor_snap, const int x, const int y) +{ + cursor_snap->last_eventstate.x = x; + cursor_snap->last_eventstate.y = y; +} + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK +static bool invert_snap(SnapCursorDataIntern *sdata_intern, const wmWindowManager *wm) +{ + if (!wm || !wm->winactive) { + return false; + } + + const wmEvent *event = wm->winactive->eventstate; + if ((event->ctrl == sdata_intern->last_eventstate.ctrl) && + (event->shift == sdata_intern->last_eventstate.shift) && + (event->alt == sdata_intern->last_eventstate.alt) && + (event->oskey == sdata_intern->last_eventstate.oskey)) { + /* Nothing has changed. */ + return sdata_intern->snap_data.is_snap_invert; + } + + /* Save new eventstate. */ + sdata_intern->last_eventstate.ctrl = event->ctrl; + sdata_intern->last_eventstate.shift = event->shift; + sdata_intern->last_eventstate.alt = event->alt; + sdata_intern->last_eventstate.oskey = event->oskey; + + const int snap_on = sdata_intern->snap_on; + + wmKeyMap *keymap = WM_keymap_active(wm, sdata_intern->keymap); + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (kmi->flag & KMI_INACTIVE) { + continue; + } + + if (kmi->propvalue == snap_on) { + if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || + (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || + (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || + ((kmi->type == EVT_OSKEY) && event->oskey)) { + return true; + } + } + } + return false; +} +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update + * \{ */ + +static short cursor_snap_elements(V3DSnapCursorData *cursor_snap, Scene *scene) +{ + short snap_elements = cursor_snap->snap_elem_force; + if (!snap_elements) { + return scene->toolsettings->snap_mode; + } + return snap_elements; +} + +static void wm_paint_cursor_snap_context_ensure(SnapCursorDataIntern *sdata_intern, Scene *scene) +{ + if (sdata_intern->snap_context_v3d == NULL) { + sdata_intern->snap_context_v3d = ED_transform_snap_object_context_create(scene, 0); + } +} + +static void cursor_snap_update(const bContext *C, + wmWindowManager *wm, + Depsgraph *depsgraph, + Scene *scene, + ARegion *region, + View3D *v3d, + int x, + int y, + SnapCursorDataIntern *sdata_intern) +{ + wm_paint_cursor_snap_context_ensure(sdata_intern, scene); + V3DSnapCursorData *snap_data = (V3DSnapCursorData *)sdata_intern; + + float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3]; + short snap_elem = 0; + int snap_elem_index[3] = {-1, -1, -1}; + int index = -1; + + const float mval_fl[2] = {x, y}; + zero_v3(no); + zero_v3(face_nor); + unit_m3(omat); + + ushort snap_elements = cursor_snap_elements(snap_data, scene); + sdata_intern->snap_elem_hidden = 0; + const bool draw_plane = sdata_intern->draw_plane; + if (draw_plane && !(snap_elements & SCE_SNAP_MODE_FACE)) { + sdata_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE; + snap_elements |= SCE_SNAP_MODE_FACE; + } + + snap_data->is_enabled = true; +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (!(snap_data->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE)) { + snap_data->is_snap_invert = invert_snap(sdata_intern, wm); + + const ToolSettings *ts = scene->toolsettings; + if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) { + snap_data->is_enabled = false; + if (!draw_plane) { + snap_data->snap_elem = 0; + return; + } + snap_elements = sdata_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE; + } + } +#endif + + if (snap_elements & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + float prev_co[3] = {0.0f}; + if (snap_data->prevpoint) { + copy_v3_v3(prev_co, snap_data->prevpoint); + } + else { + snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; + } + + eSnapSelect snap_select = (snap_data->flag & V3D_SNAPCURSOR_SNAP_ONLY_ACTIVE) ? + SNAP_ONLY_ACTIVE : + SNAP_ALL; + + eSnapEditType edit_mode_type = (snap_data->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL) ? + SNAP_GEOM_FINAL : + (snap_data->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE) ? + SNAP_GEOM_CAGE : + SNAP_GEOM_EDIT; + + bool use_occlusion_test = (snap_data->flag & V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE) ? false : + true; + + float dist_px = 12.0f * U.pixelsize; + + snap_elem = ED_transform_snap_object_project_view3d_ex( + sdata_intern->snap_context_v3d, + depsgraph, + region, + v3d, + snap_elements, + &(const struct SnapObjectParams){ + .snap_select = snap_select, + .edit_mode_type = edit_mode_type, + .use_occlusion_test = use_occlusion_test, + }, + mval_fl, + prev_co, + &dist_px, + co, + no, + &index, + NULL, + obmat, + face_nor); + } + + if (is_zero_v3(face_nor)) { + face_nor[snap_data->plane_axis] = 1.0f; + } + + if (draw_plane) { + bool orient_surface = snap_elem && (snap_data->plane_orient == V3D_PLACE_ORIENT_SURFACE); + if (orient_surface) { + copy_m3_m4(omat, obmat); + } + else { + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + const short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); + const int pivot_point = scene->toolsettings->transform_pivot_point; + ED_transform_calc_orientation_from_type_ex( + scene, view_layer, v3d, region->regiondata, ob, ob, orient_index, pivot_point, omat); + + RegionView3D *rv3d = region->regiondata; + if (snap_data->use_plane_axis_auto) { + mat3_align_axis_to_v3(omat, snap_data->plane_axis, rv3d->viewinv[2]); + } + } + + /* Non-orthogonal matrices cause the preview and final result not to match. + * + * While making orthogonal doesn't always work well (especially with gimbal orientation for + * e.g.) it's a corner case, without better alternatives as objects don't support shear. */ + orthogonalize_m3(omat, snap_data->plane_axis); + + if (orient_surface) { + cursor_poject_surface_normal(snap_data->face_nor, obmat, omat); + } + } + + float *co_depth = snap_elem ? co : scene->cursor.location; + snap_elem &= ~sdata_intern->snap_elem_hidden; + if (snap_elem == 0) { + float plane[4]; + if (snap_data->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) { + const float *plane_normal = omat[snap_data->plane_axis]; + plane_from_point_normal_v3(plane, co_depth, plane_normal); + } + + if ((snap_data->plane_depth == V3D_PLACE_DEPTH_CURSOR_VIEW) || + !ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, true, co)) { + ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, co); + } + + if (snap_data->is_enabled && (snap_elements & SCE_SNAP_MODE_INCREMENT)) { + cursor_snap_calc_incremental(scene, v3d, region, snap_data->prevpoint, co); + } + } + else if (snap_elem == SCE_SNAP_MODE_VERTEX) { + snap_elem_index[0] = index; + } + else if (snap_elem & + (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + snap_elem_index[1] = index; + } + else if (snap_elem == SCE_SNAP_MODE_FACE) { + snap_elem_index[2] = index; + } + + snap_data->snap_elem = snap_elem; + copy_v3_v3(snap_data->loc, co); + copy_v3_v3(snap_data->nor, no); + copy_v3_v3(snap_data->face_nor, face_nor); + copy_m4_m4(snap_data->obmat, obmat); + copy_v3_v3_int(snap_data->elem_index, snap_elem_index); + + copy_m3_m3(snap_data->plane_omat, omat); + + eventstate_save_xy(sdata_intern, x, y); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks + * \{ */ + +static bool cursor_snap_pool_fn(bContext *C) +{ + if (G.moving) { + return false; + } + + ARegion *region = CTX_wm_region(C); + if (region->regiontype != RGN_TYPE_WINDOW) { + return false; + } + + ScrArea *area = CTX_wm_area(C); + if (area->spacetype != SPACE_VIEW3D) { + return false; + } + + RegionView3D *rv3d = region->regiondata; + if (rv3d->rflag & RV3D_NAVIGATING) { + /* Don't draw the cursor while navigating. It can be distracting. */ + return false; + }; + + return true; +} + +static void cursor_snap_draw_fn(bContext *C, int x, int y, void *customdata) +{ + V3DSnapCursorData *snap_data = customdata; + SnapCursorDataIntern *sdata_intern = customdata; + + wmWindowManager *wm = CTX_wm_manager(C); + ARegion *region = CTX_wm_region(C); + x -= region->winrct.xmin; + y -= region->winrct.ymin; + if (eventstate_has_changed(sdata_intern, wm, x, y)) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = DEG_get_input_scene(depsgraph); + View3D *v3d = CTX_wm_view3d(C); + cursor_snap_update(C, wm, depsgraph, scene, region, v3d, x, y, sdata_intern); + } + + const bool draw_plane = sdata_intern->draw_plane; + if (!snap_data->snap_elem && !draw_plane) { + return; + } + + /* Setup viewport & matrix. */ + RegionView3D *rv3d = region->regiondata; + wmViewport(®ion->winrct); + GPU_matrix_push_projection(); + GPU_matrix_push(); + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); + + GPU_blend(GPU_BLEND_ALPHA); + + float matrix[4][4]; + if (draw_plane) { + copy_m4_m3(matrix, snap_data->plane_omat); + copy_v3_v3(matrix[3], snap_data->loc); + + cursor_plane_draw(rv3d, snap_data->plane_axis, matrix); + } + + if (snap_data->snap_elem && sdata_intern->draw_point) { + const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ? + snap_data->prevpoint : + NULL; + + GPU_line_smooth(false); + GPU_line_width(1.0f); + + ED_view3d_cursor_snap_draw_util(rv3d, + prev_point, + snap_data->loc, + NULL, + snap_data->color_line, + snap_data->color_point, + snap_data->snap_elem); + } + + GPU_blend(GPU_BLEND_NONE); + + /* Restore matrix. */ + GPU_matrix_pop(); + GPU_matrix_pop_projection(); +} + +/** \} */ + +V3DSnapCursorData *ED_view3d_cursor_snap_data_get(void) +{ + LISTBASE_FOREACH_MUTABLE (wmWindowManager *, wm, &G.main->wm) { + LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) { + if (pc->draw == cursor_snap_draw_fn) { + return (V3DSnapCursorData *)pc->customdata; + } + } + } + return NULL; +} + +static void wm_paint_cursor_snap_data_init(SnapCursorDataIntern *sdata_intern) +{ +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + struct wmKeyConfig *keyconf = ((wmWindowManager *)G.main->wm.first)->defaultconf; + + sdata_intern->keymap = WM_modalkeymap_find(keyconf, "Generic Gizmo Tweak Modal Map"); + RNA_enum_value_from_id(sdata_intern->keymap->modal_items, "SNAP_ON", &sdata_intern->snap_on); +#endif + + V3DSnapCursorData *snap_data = &sdata_intern->snap_data; + snap_data->snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT); + snap_data->plane_axis = 2; + rgba_uchar_args_set(snap_data->color_point, 255, 255, 255, 255); + UI_GetThemeColor3ubv(TH_TRANSFORM, snap_data->color_line); + snap_data->color_line[3] = 128; +} + +static SnapCursorDataIntern *wm_paint_cursor_snap_ensure(void) +{ + SnapCursorDataIntern *sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + sdata_intern = MEM_callocN(sizeof(*sdata_intern), __func__); + wm_paint_cursor_snap_data_init(sdata_intern); + + struct wmPaintCursor *pc = WM_paint_cursor_activate( + SPACE_VIEW3D, RGN_TYPE_WINDOW, cursor_snap_pool_fn, cursor_snap_draw_fn, sdata_intern); + sdata_intern->handle = pc; + } + return sdata_intern; +} + +void ED_view3d_cursor_snap_activate_point(void) +{ + SnapCursorDataIntern *sdata_intern = wm_paint_cursor_snap_ensure(); + sdata_intern->draw_point = true; +} + +void ED_view3d_cursor_snap_activate_plane(void) +{ + SnapCursorDataIntern *sdata_intern = wm_paint_cursor_snap_ensure(); + sdata_intern->draw_plane = true; +} + +static void wm_paint_cursor_snap_free(SnapCursorDataIntern *sdata_intern) +{ + WM_paint_cursor_end(sdata_intern->handle); + if (sdata_intern->snap_context_v3d) { + ED_transform_snap_object_context_destroy(sdata_intern->snap_context_v3d); + } + MEM_freeN(sdata_intern); +} + +void ED_view3d_cursor_snap_deactivate_point(void) +{ + SnapCursorDataIntern *sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + return; + } + + sdata_intern->draw_point = false; + sdata_intern->snap_data.prevpoint = NULL; + if (sdata_intern->draw_plane) { + return; + } + + wm_paint_cursor_snap_free(sdata_intern); +} + +void ED_view3d_cursor_snap_deactivate_plane(void) +{ + SnapCursorDataIntern *sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + return; + } + + sdata_intern->draw_plane = false; + sdata_intern->snap_data.prevpoint = NULL; + if (sdata_intern->draw_point) { + return; + } + + wm_paint_cursor_snap_free(sdata_intern); +} + +void ED_view3d_cursor_snap_update(const bContext *C, + const int x, + const int y, + V3DSnapCursorData *snap_data) +{ + SnapCursorDataIntern stack = {0}, *sdata_intern; + sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + sdata_intern = &stack; + wm_paint_cursor_snap_data_init(sdata_intern); + sdata_intern->draw_plane = true; + } + + wmWindowManager *wm = CTX_wm_manager(C); + if (eventstate_has_changed(sdata_intern, wm, x, y)) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = DEG_get_input_scene(depsgraph); + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + + cursor_snap_update(C, wm, depsgraph, scene, region, v3d, x, y, sdata_intern); + } + if ((void *)snap_data != (void *)sdata_intern) { + if ((sdata_intern == &stack) && sdata_intern->snap_context_v3d) { + ED_transform_snap_object_context_destroy(sdata_intern->snap_context_v3d); + sdata_intern->snap_context_v3d = NULL; + } + *snap_data = *(V3DSnapCursorData *)sdata_intern; + } +} + +void ED_view3d_cursor_snap_prevpoint_set(const float prev_point[3]) +{ + SnapCursorDataIntern *sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + return; + } + if (prev_point) { + copy_v3_v3(sdata_intern->prevpoint_stack, prev_point); + sdata_intern->snap_data.prevpoint = sdata_intern->prevpoint_stack; + } + else { + sdata_intern->snap_data.prevpoint = NULL; + } +} + +struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene) +{ + SnapCursorDataIntern *sdata_intern = (SnapCursorDataIntern *)ED_view3d_cursor_snap_data_get(); + if (!sdata_intern) { + return NULL; + } + wm_paint_cursor_snap_context_ensure(sdata_intern, scene); + return sdata_intern->snap_context_v3d; +} diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d34fbc4562a..ba9b104a9cc 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -5122,7 +5122,8 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, ray_no, NULL, &ob_dummy, - obmat) != 0) { + obmat, + NULL) != 0) { if (use_depth) { copy_v3_v3(cursor_co, ray_co); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 573f5348b5e..34e3b808b50 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -332,7 +332,8 @@ static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], cons /** * Use for mouse-move events. */ -static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, +static bool view3d_ruler_item_mousemove(const bContext *C, + struct Depsgraph *depsgraph, RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], @@ -401,7 +402,6 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, #endif { View3D *v3d = ruler_info->area->spacedata.first; - const float mval_fl[2] = {UNPACK2(mval)}; float *prev_point = NULL; if (inter->co_index != 1) { @@ -420,11 +420,8 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); } - ED_gizmotypes_snap_3d_update( - snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl); - if (ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)) { - ED_gizmotypes_snap_3d_data_get(snap_gizmo, co, NULL, NULL, NULL); + ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, NULL, NULL, NULL); } #ifdef USE_AXIS_CONSTRAINTS @@ -1050,7 +1047,8 @@ static int gizmo_ruler_modal(bContext *C, 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, + if (view3d_ruler_item_mousemove(C, + depsgraph, ruler_info, ruler_item, event->mval, @@ -1117,7 +1115,8 @@ 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, + view3d_ruler_item_mousemove(C, + depsgraph, ruler_info, ruler_item_pick, event->mval, @@ -1236,7 +1235,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) (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)); - ED_gizmotypes_snap_3d_flag_set(gizmo, ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE); + ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE); 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); @@ -1321,7 +1320,8 @@ 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, + view3d_ruler_item_mousemove(C, + depsgraph, ruler_info, ruler_item, event->mval, diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 6cd6d85d204..adff75b571d 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -25,17 +25,7 @@ #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_global.h" -#include "BKE_main.h" #include "RNA_access.h" #include "RNA_define.h" @@ -43,29 +33,23 @@ #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_matrix.h" -#include "GPU_state.h" #include "view3d_intern.h" static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; -static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup); -static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw); +static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, + bool do_draw_plane, + bool do_draw_point); /** * Dot products below this will be considered view aligned. @@ -96,17 +80,6 @@ enum ePlace_Aspect { PLACE_ASPECT_FIXED = 2, }; -enum ePlace_Depth { - PLACE_DEPTH_SURFACE = 1, - PLACE_DEPTH_CURSOR_PLANE = 2, - PLACE_DEPTH_CURSOR_VIEW = 3, -}; - -enum ePlace_Orient { - PLACE_ORIENT_SURFACE = 1, - PLACE_ORIENT_DEFAULT = 2, -}; - enum ePlace_SnapTo { PLACE_SNAP_TO_GEOMETRY = 1, PLACE_SNAP_TO_DEFAULT = 2, @@ -198,9 +171,6 @@ struct InteractivePlaceData { /** When activated without a tool. */ bool wait_for_input; - /** Optional snap gizmo, needed for snapping. */ - wmGizmo *snap_gizmo; - enum ePlace_SnapTo snap_to; }; @@ -251,130 +221,6 @@ static int dot_v3_array_find_max_index(const float dirs[][3], return index_found; } -/** - * Re-order \a mat so \a axis_align uses its own axis which is closest to \a v. - */ -static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3]) -{ - float dot_best = -1.0f; - int axis_found = axis_align; - for (int i = 0; i < 3; i++) { - const float dot_test = fabsf(dot_v3v3(mat[i], v)); - if (dot_test > dot_best) { - dot_best = dot_test; - axis_found = i; - } - } - - if (axis_align != axis_found) { - float tmat[3][3]; - copy_m3_m3(tmat, mat); - const int offset = mod_i(axis_found - axis_align, 3); - for (int i = 0; i < 3; i++) { - copy_v3_v3(mat[i], tmat[(i + offset) % 3]); - } - return true; - } - return false; -} - -/* On-screen snap distance. */ -#define MVAL_MAX_PX_DIST 12.0f - -static bool idp_snap_point_from_gizmo_ex(wmGizmo *gz, const char *prop_id, float r_location[3]) -{ - if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { - PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, prop_id); - RNA_property_float_get_array(gz->ptr, prop_location, r_location); - return true; - } - return false; -} - -static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3]) -{ - return idp_snap_point_from_gizmo_ex(gz, "location", r_location); -} - -static bool idp_snap_normal_from_gizmo(wmGizmo *gz, float r_normal[3]) -{ - return idp_snap_point_from_gizmo_ex(gz, "normal", r_normal); -} - -/** - * Calculate a 3x3 orientation matrix from the surface under the cursor. - */ -static bool idp_poject_surface_normal(SnapObjectContext *snap_context, - struct Depsgraph *depsgraph, - ARegion *region, - View3D *v3d, - const float mval_fl[2], - const float mat_fallback[3][3], - const float normal_fallback[3], - float r_mat[3][3]) -{ - bool success = false; - float normal[3] = {0.0f}; - float co_dummy[3]; - /* We could use the index to get the orientation from the face. */ - Object *ob_snap; - float obmat[4][4]; - - if (ED_transform_snap_object_project_view3d_ex(snap_context, - depsgraph, - region, - v3d, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .edit_mode_type = SNAP_GEOM_EDIT, - }, - mval_fl, - NULL, - NULL, - co_dummy, - normal, - NULL, - &ob_snap, - obmat)) { - /* pass */ - } - else if (normal_fallback != NULL) { - copy_m4_m3(obmat, mat_fallback); - copy_v3_v3(normal, normal_fallback); - } - - if (!is_zero_v3(normal)) { - float mat[3][3]; - copy_m3_m4(mat, obmat); - normalize_m3(mat); - - float dot_best = fabsf(dot_v3v3(mat[0], normal)); - int i_best = 0; - for (int i = 1; i < 3; i++) { - float dot_test = fabsf(dot_v3v3(mat[i], normal)); - if (dot_test > dot_best) { - i_best = i; - dot_best = dot_test; - } - } - if (dot_v3v3(mat[i_best], normal) < 0.0f) { - negate_v3(mat[(i_best + 1) % 3]); - negate_v3(mat[(i_best + 2) % 3]); - } - copy_v3_v3(mat[i_best], normal); - orthogonalize_m3(mat, i_best); - normalize_m3(mat); - - copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]); - copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]); - copy_v3_v3(r_mat[2], mat[i_best]); - success = true; - } - - return success; -} - static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region) { wmGizmoMap *gzmap = region->gizmo_map; @@ -417,20 +263,6 @@ static bool idp_snap_calc_incremental( return true; } -static void idp_snap_gizmo_update_snap_elements(Scene *scene, - enum ePlace_SnapTo snap_to, - wmGizmo *gizmo) -{ - const int snap_mode = - (snap_to == PLACE_SNAP_TO_GEOMETRY) ? - (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) : - scene->toolsettings->snap_mode; - - RNA_enum_set(gizmo->ptr, "snap_elements_force", snap_mode); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -861,153 +693,18 @@ static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region * Use by both the operator and placement cursor. * \{ */ -static void view3d_interactive_add_calc_plane(bContext *C, - Scene *scene, - View3D *v3d, - ARegion *region, - const float mval_fl[2], - wmGizmo *snap_gizmo, - const enum ePlace_SnapTo snap_to, - const enum ePlace_Depth plane_depth, - const enum ePlace_Orient plane_orient, - const int plane_axis, - const bool plane_axis_auto, +static bool view3d_interactive_add_calc_plane(bContext *C, + const wmEvent *event, float r_co_src[3], float r_matrix_orient[3][3]) { - const RegionView3D *rv3d = region->regiondata; - ED_transform_calc_orientation_from_type(C, r_matrix_orient); - - /* Non-orthogonal matrices cause the preview and final result not to match. - * - * While making orthogonal doesn't always work well (especially with gimbal orientation for e.g.) - * it's a corner case, without better alternatives as objects don't support shear. */ - orthogonalize_m3(r_matrix_orient, plane_axis); - - SnapObjectContext *snap_context = NULL; - bool snap_context_free = false; - - /* Set the orientation. */ - if ((plane_orient == PLACE_ORIENT_SURFACE) || (plane_depth == PLACE_DEPTH_SURFACE)) { - snap_context = (snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo) : NULL); - if (snap_context == NULL) { - snap_context = ED_transform_snap_object_context_create(scene, 0); - snap_context_free = true; - } - } - - if (plane_orient == PLACE_ORIENT_SURFACE) { - bool found_surface_or_normal = false; - float matrix_orient_surface[3][3]; - - /* Use the snap normal as a fallback in case the cursor isn't over a surface - * but snapping is enabled. */ - float normal_fallback[3]; - bool use_normal_fallback = snap_gizmo ? - idp_snap_normal_from_gizmo(snap_gizmo, normal_fallback) : - false; - - if ((snap_context != NULL) && - idp_poject_surface_normal(snap_context, - CTX_data_ensure_evaluated_depsgraph(C), - region, - v3d, - mval_fl, - use_normal_fallback ? r_matrix_orient : NULL, - use_normal_fallback ? normal_fallback : NULL, - matrix_orient_surface)) { - copy_m3_m3(r_matrix_orient, matrix_orient_surface); - found_surface_or_normal = true; - } - - if (!found_surface_or_normal && plane_axis_auto) { - /* Drawing into empty space, draw onto the plane most aligned to the view direction. */ - mat3_align_axis_to_v3(r_matrix_orient, plane_axis, rv3d->viewinv[2]); - } - } - - const bool is_snap_found = snap_gizmo ? idp_snap_point_from_gizmo(snap_gizmo, r_co_src) : false; - - 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(v3d, region, scene->cursor.location, mval_fl, r_co_src); - use_depth_fallback = false; - } - else if (plane_depth == PLACE_DEPTH_SURFACE) { - if ((snap_context != NULL) && - ED_transform_snap_object_project_view3d(snap_context, - CTX_data_ensure_evaluated_depsgraph(C), - region, - v3d, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .edit_mode_type = SNAP_GEOM_EDIT, - }, - mval_fl, - NULL, - NULL, - r_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]; - const float *plane_normal = r_matrix_orient[plane_axis]; - - const float view_axis_dot = fabsf(dot_v3v3(rv3d->viewinv[2], r_matrix_orient[plane_axis])); - if (view_axis_dot < eps_view_align) { - /* In this case, just project onto the view plane as it's important the location - * is _always_ under the mouse cursor, even if it turns out that won't lie on - * the original 'plane' that's been calculated for us. */ - plane_normal = rv3d->viewinv[2]; - } - - plane_from_point_normal_v3(plane, scene->cursor.location, plane_normal); - - if (view3d_win_to_3d_on_plane_maybe_fallback(region, plane, mval_fl, NULL, r_co_src)) { - use_depth_fallback = false; - } - - /* Even if the calculation works, it's possible the point found is behind the view, - * or very far away (past the far clipping). - * In either case creating objects won't be useful. */ - if (rv3d->is_persp) { - float dir[3]; - sub_v3_v3v3(dir, rv3d->viewinv[3], r_co_src); - const float dot = dot_v3v3(dir, rv3d->viewinv[2]); - if (dot < v3d->clip_start || dot > v3d->clip_end) { - 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(v3d, region, co_depth, mval_fl, r_co_src); - } - } - - if (!is_snap_found && ((snap_gizmo != NULL) && ED_gizmotypes_snap_3d_is_enabled(snap_gizmo))) { - if (snap_to == PLACE_SNAP_TO_DEFAULT) { - idp_snap_calc_incremental(scene, v3d, region, NULL, r_co_src); - } - } - - if (snap_context_free) { - ED_transform_snap_object_context_destroy(snap_context); + V3DSnapCursorData snap_data; + ED_view3d_cursor_snap_update(C, UNPACK2(event->mval), &snap_data); + copy_v3_v3(r_co_src, snap_data.loc); + if (r_matrix_orient) { + copy_m3_m3(r_matrix_orient, snap_data.plane_omat); } + return snap_data.snap_elem != 0; } /** \} */ @@ -1022,7 +719,8 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); const bool plane_axis_auto = RNA_boolean_get(op->ptr, "plane_axis_auto"); const enum ePlace_SnapTo snap_to = RNA_enum_get(op->ptr, "snap_target"); - const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth"); + const eV3DPlaceDepth plane_depth = RNA_enum_get(op->ptr, "plane_depth"); + const eV3DPlaceOrient plane_orient = RNA_enum_get(op->ptr, "plane_orient"); const enum ePlace_Origin plane_origin[2] = { RNA_enum_get(op->ptr, "plane_origin_base"), RNA_enum_get(op->ptr, "plane_origin_depth"), @@ -1031,58 +729,29 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv RNA_enum_get(op->ptr, "plane_aspect_base"), RNA_enum_get(op->ptr, "plane_aspect_depth"), }; - const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation"); - - const float mval_fl[2] = {UNPACK2(event->mval)}; struct InteractivePlaceData *ipd = op->customdata; - /* Assign snap gizmo which is may be used as part of the tool. */ - { - wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region); - if (gzgroup != NULL) { - if (gzgroup->gizmos.first) { - ipd->snap_gizmo = gzgroup->gizmos.first; - } + ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type); - /* Can be NULL when gizmos are disabled. */ - if (gzgroup->customdata != NULL) { - preview_plane_cursor_visible_set(gzgroup, false); - } - } - } + ED_view3d_cursor_snap_activate_point(); + { + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + snap_data->plane_depth = plane_depth; + snap_data->plane_orient = plane_orient; + snap_data->plane_axis = plane_axis; + snap_data->use_plane_axis_auto = plane_axis_auto; - /* For tweak events the snap target may have changed since dragging, - * update the snap target at the cursor location where tweak began. - * - * NOTE: we could investigating solving this in a more generic way, - * so each operator doesn't have to account for it. */ - if (ISTWEAK(event->type)) { - if (ipd->snap_gizmo != NULL) { - ED_gizmotypes_snap_3d_update(ipd->snap_gizmo, - CTX_data_ensure_evaluated_depsgraph(C), - ipd->region, - ipd->v3d, - G_MAIN->wm.first, - mval_fl); - } - } + ED_view3d_cursor_snap_activate_plane(); + view3d_interactive_add_calc_plane(C, event, ipd->co_src, ipd->matrix_orient); + ED_view3d_cursor_snap_deactivate_plane(); - ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type); + ED_view3d_cursor_snap_prevpoint_set(ipd->co_src); - view3d_interactive_add_calc_plane(C, - ipd->scene, - ipd->v3d, - ipd->region, - mval_fl, - ipd->snap_gizmo, - snap_to, - plane_depth, - plane_orient, - plane_axis, - plane_axis_auto, - ipd->co_src, - ipd->matrix_orient); + ipd->use_snap = snap_data->is_enabled; + ipd->is_snap_invert = snap_data->is_snap_invert; + ipd->is_snap_found = snap_data->snap_elem != 0; + } ipd->orient_axis = plane_axis; for (int i = 0; i < 2; i++) { @@ -1161,13 +830,6 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv } } - 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)); - } - ipd->draw_handle_view = ED_region_draw_cb_activate( ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW); @@ -1244,19 +906,18 @@ static void view3d_interactive_add_exit(bContext *C, wmOperator *op) struct InteractivePlaceData *ipd = op->customdata; + wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region); + if (gzgroup != NULL) { + preview_plane_cursor_visible_set(gzgroup, true, true); + } + else { + ED_view3d_cursor_snap_deactivate_point(); + } + ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); ED_region_tag_redraw(ipd->region); - { - wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region); - if (gzgroup != NULL) { - if (gzgroup->customdata != NULL) { - preview_plane_cursor_visible_set(gzgroup, true); - } - } - } - MEM_freeN(ipd); } @@ -1374,6 +1035,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve if (ipd->step_index == STEP_BASE) { if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) { if (event->val == KM_RELEASE) { + ED_view3d_cursor_snap_prevpoint_set(ipd->co_src); + /* Set secondary plane. */ /* Create normal. */ @@ -1521,19 +1184,7 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve /* Calculate the snap location on mouse-move or when toggling snap. */ ipd->is_snap_found = false; if (ipd->use_snap) { - if (ipd->snap_gizmo != NULL) { - ED_gizmotypes_snap_3d_flag_set(ipd->snap_gizmo, ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE); - if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo, - CTX_data_ensure_evaluated_depsgraph(C), - ipd->region, - ipd->v3d, - G_MAIN->wm.first, - mval_fl)) { - ED_gizmotypes_snap_3d_data_get(ipd->snap_gizmo, ipd->snap_co, NULL, NULL, NULL); - ipd->is_snap_found = true; - } - ED_gizmotypes_snap_3d_flag_clear(ipd->snap_gizmo, ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE); - } + ipd->is_snap_found = view3d_interactive_add_calc_plane(C, event, ipd->snap_co, NULL); } if (ipd->step_index == STEP_BASE) { @@ -1632,6 +1283,7 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) {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); @@ -1652,18 +1304,18 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); static const EnumPropertyItem plane_depth_items[] = { - {PLACE_DEPTH_SURFACE, + {V3D_PLACE_DEPTH_SURFACE, "SURFACE", 0, "Surface", "Start placing on the surface, using the 3D cursor position as a fallback"}, - {PLACE_DEPTH_CURSOR_PLANE, + {V3D_PLACE_DEPTH_CURSOR_PLANE, "CURSOR_PLANE", 0, "Cursor Plane", "Start placement using a point projected onto the orientation axis " "at the 3D cursor position"}, - {PLACE_DEPTH_CURSOR_VIEW, + {V3D_PLACE_DEPTH_CURSOR_VIEW, "CURSOR_VIEW", 0, "Cursor View", @@ -1672,17 +1324,17 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) }; 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_default(prop, V3D_PLACE_DEPTH_SURFACE); RNA_def_property_enum_items(prop, plane_depth_items); RNA_def_property_flag(prop, PROP_SKIP_SAVE); static const EnumPropertyItem plane_orientation_items[] = { - {PLACE_ORIENT_SURFACE, + {V3D_PLACE_ORIENT_SURFACE, "SURFACE", ICON_SNAP_NORMAL, "Surface", "Use the surface normal (using the transform orientation as a fallback)"}, - {PLACE_ORIENT_DEFAULT, + {V3D_PLACE_ORIENT_DEFAULT, "DEFAULT", ICON_ORIENTATION_GLOBAL, "Default", @@ -1691,7 +1343,7 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) }; prop = RNA_def_property(ot->srna, "plane_orientation", PROP_ENUM, PROP_NONE); RNA_def_property_ui_text(prop, "Orientation", "The initial depth used when placing the cursor"); - RNA_def_property_enum_default(prop, PLACE_ORIENT_SURFACE); + RNA_def_property_enum_default(prop, V3D_PLACE_ORIENT_SURFACE); RNA_def_property_enum_items(prop, plane_orientation_items); RNA_def_property_flag(prop, PROP_SKIP_SAVE); @@ -1752,388 +1404,90 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) * we could show a placement plane here. * \{ */ -static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +static void preview_plane_cursor_visible_set(wmGizmoGroup *UNUSED(gzgroup), + bool do_draw_plane, + bool do_draw_point) { - 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); - - WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); - /* Don't handle any events, this is for display only. */ - gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; + if (do_draw_point) { + ED_view3d_cursor_snap_activate_point(); } - /* Sets the gizmos custom-data which has its own free callback. */ - preview_plane_cursor_setup(gzgroup); -} - -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; + if (do_draw_plane) { + ED_view3d_cursor_snap_activate_plane(); + } + else { + ED_view3d_cursor_snap_deactivate_plane(); + } - gzgt->gzmap_params.spaceid = SPACE_VIEW3D; - gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + if (!do_draw_point) { + ED_view3d_cursor_snap_deactivate_point(); + } - gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; - gzgt->setup = WIDGETGROUP_placement_setup; + if (!snap_data && (do_draw_point || do_draw_plane)) { + snap_data = ED_view3d_cursor_snap_data_get(); + UI_GetThemeColor3ubv(TH_TRANSFORM, snap_data->color_line); + snap_data->color_line[3] = 128; + rgba_uchar_args_set(snap_data->color_point, 255, 255, 255, 255); + } } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Placement Preview Plane - * - * Preview the plane that will be used for placement. - * - * Note that we might want to split this into its own file, - * for now this is coupled with the 3D view placement gizmo. - * \{ */ - -static void gizmo_plane_update_cursor(const bContext *C, - ARegion *region, - const int mval[2], - float r_co[3], - float r_matrix_orient[3][3], - int *r_plane_axis) +static void preview_plane_free_fn(void *customdata) { - wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_interactive_add", true); - BLI_assert(ot != NULL); - PointerRNA ptr; - - ScrArea *area = CTX_wm_area(C); - BLI_assert(region == CTX_wm_region(C)); - bToolRef *tref = area->runtime.tool; - WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, &ptr); - - const enum ePlace_SnapTo snap_to = RNA_enum_get(&ptr, "snap_target"); - const int plane_axis = RNA_enum_get(&ptr, "plane_axis"); - const bool plane_axis_auto = RNA_boolean_get(&ptr, "plane_axis_auto"); - const enum ePlace_Depth plane_depth = RNA_enum_get(&ptr, "plane_depth"); - const enum ePlace_Orient plane_orient = RNA_enum_get(&ptr, "plane_orientation"); - - const float mval_fl[2] = {UNPACK2(mval)}; - - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - - /* Assign snap gizmo which is may be used as part of the tool. */ - wmGizmo *snap_gizmo = NULL; - { - wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region); - if ((gzgroup != NULL) && gzgroup->gizmos.first) { - snap_gizmo = gzgroup->gizmos.first; - } - } - - /* This ensures the snap gizmo has settings from this tool. - * This function call could be moved a more appropriate place, - * responding to the setting being changed for example, - * however setting the value isn't expensive, so do it here. */ - idp_snap_gizmo_update_snap_elements(scene, snap_to, snap_gizmo); - - view3d_interactive_add_calc_plane((bContext *)C, - scene, - v3d, - region, - mval_fl, - snap_gizmo, - snap_to, - plane_depth, - plane_orient, - plane_axis, - plane_axis_auto, - r_co, - r_matrix_orient); - *r_plane_axis = plane_axis; + preview_plane_cursor_visible_set(customdata, false, false); } -static void gizmo_plane_draw_grid(const int resolution, - const float scale, - const float scale_fade, - const float matrix[4][4], - const int plane_axis, - const float color[4]) +static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - BLI_assert(scale_fade <= scale); - const int resolution_min = resolution - 1; - float color_fade[4] = {UNPACK4(color)}; - const float *center = matrix[3]; - - GPU_blend(GPU_BLEND_ADDITIVE); - GPU_line_smooth(true); - GPU_line_width(1.0f); - - GPUVertFormat *format = immVertexFormat(); - const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - const uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); - - const size_t coords_len = resolution * resolution; - float(*coords)[3] = MEM_mallocN(sizeof(*coords) * coords_len, __func__); - - const int axis_x = (plane_axis + 0) % 3; - const int axis_y = (plane_axis + 1) % 3; - const int axis_z = (plane_axis + 2) % 3; - - int i; - const float resolution_div = (float)1.0f / (float)resolution; - i = 0; - for (int x = 0; x < resolution; x++) { - const float x_fl = (x * resolution_div) - 0.5f; - for (int y = 0; y < resolution; y++) { - const float y_fl = (y * resolution_div) - 0.5f; - coords[i][axis_x] = 0.0f; - coords[i][axis_y] = x_fl * scale; - coords[i][axis_z] = y_fl * scale; - mul_m4_v3(matrix, coords[i]); - i += 1; - } - } - BLI_assert(i == coords_len); - immBeginAtMost(GPU_PRIM_LINES, coords_len * 4); - i = 0; - for (int x = 0; x < resolution_min; x++) { - for (int y = 0; y < resolution_min; y++) { - - /* Add #resolution_div to ensure we fade-out entirely. */ -#define FADE(v) \ - max_ff(0.0f, (1.0f - square_f(((len_v3v3(v, center) / scale_fade) + resolution_div) * 2.0f))) - - const float *v0 = coords[(resolution * x) + y]; - const float *v1 = coords[(resolution * (x + 1)) + y]; - const float *v2 = coords[(resolution * x) + (y + 1)]; - - const float f0 = FADE(v0); - const float f1 = FADE(v1); - const float f2 = FADE(v2); - - if (f0 > 0.0f || f1 > 0.0f) { - color_fade[3] = color[3] * f0; - immAttr4fv(col_id, color_fade); - immVertex3fv(pos_id, v0); - color_fade[3] = color[3] * f1; - immAttr4fv(col_id, color_fade); - immVertex3fv(pos_id, v1); - } - if (f0 > 0.0f || f2 > 0.0f) { - color_fade[3] = color[3] * f0; - immAttr4fv(col_id, color_fade); - immVertex3fv(pos_id, v0); - - color_fade[3] = color[3] * f2; - immAttr4fv(col_id, color_fade); - immVertex3fv(pos_id, v2); - } - -#undef FADE - - i++; - } - } - - MEM_freeN(coords); - - immEnd(); - - immUnbindProgram(); - - GPU_line_smooth(false); - GPU_blend(GPU_BLEND_NONE); + preview_plane_cursor_visible_set(gzgroup, true, true); + gzgroup->customdata = gzgroup; + gzgroup->customdata_free = preview_plane_free_fn; } -/* -------------------------------------------------------------------- */ -/** \name Preview Plane Cursor - * \{ */ - -struct PlacementCursor { - /** - * Back-pointer to the gizmo-group that uses this cursor. - * Needed so we know that the cursor belongs to the region. - */ - wmGizmoGroup *gzgroup; - - /** - * Enable this while the modal operator is running, - * so the preview-plane doesn't show at the same time as add-object preview shape - * since it's distracting & not helpful. - */ - bool do_draw; - - void *paintcursor; - - int plane_axis; - float matrix[4][4]; - - /* Check if we need to re-calculate the plane matrix. */ - int mval_prev[2]; - float persmat_prev[4][4]; -}; - -static void cursor_plane_draw(bContext *C, int x, int y, void *customdata) +static void WIDGETGROUP_placement_draw_prepare(const bContext *C, wmGizmoGroup *UNUSED(gzgroup)) { - struct PlacementCursor *plc = (struct PlacementCursor *)customdata; - ARegion *region = CTX_wm_region(C); - const RegionView3D *rv3d = region->regiondata; - - /* Early exit. - * Note that we can't do most of these checks in the poll function (besides global checks) - * so test them here instead. - * - * This cursor is only active while the gizmo is being used - * so it's not so important to have a poll function. */ - if (plc->do_draw == false) { - return; - } - if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) { - return; - } - if (rv3d->rflag & RV3D_NAVIGATING) { + V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); + if (!snap_data) { return; } - /* Check this gizmo group is in the region. */ + PointerRNA ptr; { - wmGizmoMap *gzmap = region->gizmo_map; - wmGizmoGroup *gzgroup_test = WM_gizmomap_group_find_ptr(gzmap, plc->gzgroup->type); - if (gzgroup_test != plc->gzgroup) { - /* Wrong viewport. */ - return; - } - } + wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_interactive_add", true); + BLI_assert(ot != NULL); - const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin}; - - /* Update matrix? */ - if ((plc->mval_prev[0] != mval[0]) || (plc->mval_prev[1] != mval[1]) || - !equals_m4m4(plc->persmat_prev, rv3d->persmat)) { - plc->mval_prev[0] = mval[0]; - plc->mval_prev[1] = mval[1]; - - float orient_matrix[3][3]; - float co[3]; - gizmo_plane_update_cursor(C, region, mval, co, orient_matrix, &plc->plane_axis); - copy_m4_m3(plc->matrix, orient_matrix); - copy_v3_v3(plc->matrix[3], co); - - copy_m4_m4(plc->persmat_prev, rv3d->persmat); - } - - /* Draw */ - float pixel_size; - - if (rv3d->is_persp) { - float center[3]; - negate_v3_v3(center, rv3d->ofs); - pixel_size = ED_view3d_pixel_size(rv3d, center); + ScrArea *area = CTX_wm_area(C); + bToolRef *tref = area->runtime.tool; + WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, &ptr); } - else { - pixel_size = ED_view3d_pixel_size(rv3d, plc->matrix[3]); - } - - if (pixel_size > FLT_EPSILON) { - - /* Arbitrary, 1.0 is a little too strong though. */ - float color_alpha = 0.75f; - if (rv3d->is_persp) { - /* Scale down the alpha when this is drawn very small, - * since the add shader causes the small size to show too dense & bright. */ - const float relative_pixel_scale = pixel_size / ED_view3d_pixel_size(rv3d, plc->matrix[3]); - if (relative_pixel_scale < 1.0f) { - color_alpha *= max_ff(square_f(relative_pixel_scale), 0.3f); - } - } - { - /* Extra adjustment when it's near view-aligned as it seems overly bright. */ - float view_vector[3]; - ED_view3d_global_to_vector(rv3d, plc->matrix[3], view_vector); - float view_dot = fabsf(dot_v3v3(plc->matrix[plc->plane_axis], view_vector)); - color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot))); - } - - /* Setup viewport & matrix. */ - wmViewport(®ion->winrct); - GPU_matrix_push_projection(); - GPU_matrix_push(); - GPU_matrix_projection_set(rv3d->winmat); - GPU_matrix_set(rv3d->viewmat); - - const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize; - - float final_scale = (scale_mod * pixel_size); - - const int lines_subdiv = 10; - int lines = lines_subdiv; - - float final_scale_fade = final_scale; - final_scale = ceil_power_of_10(final_scale); - - float fac = final_scale_fade / final_scale; - - float color[4] = {1, 1, 1, color_alpha}; - color[3] *= square_f(1.0f - fac); - if (color[3] > 0.0f) { - gizmo_plane_draw_grid(lines * lines_subdiv, - final_scale, - final_scale_fade, - plc->matrix, - plc->plane_axis, - color); - } - - color[3] = color_alpha; - /* When the grid is large, we only need the 2x lines in the middle. */ - if (fac < 0.2f) { - lines = 1; - final_scale = final_scale_fade; - } - gizmo_plane_draw_grid( - lines, final_scale, final_scale_fade, plc->matrix, plc->plane_axis, color); - - /* Restore matrix. */ - GPU_matrix_pop(); - GPU_matrix_pop_projection(); - } + short snap_mode = 0; /* #toolsettings->snap_mode. */ + const enum ePlace_SnapTo snap_to = RNA_enum_get(&ptr, "snap_target"); + if (snap_to == PLACE_SNAP_TO_GEOMETRY) { + snap_mode = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT); + } + snap_data->snap_elem_force = snap_mode; + snap_data->plane_depth = (eV3DPlaceDepth)RNA_enum_get(&ptr, "plane_depth"); + snap_data->plane_orient = (eV3DPlaceOrient)RNA_enum_get(&ptr, "plane_orientation"); + snap_data->plane_axis = RNA_enum_get(&ptr, "plane_axis"); + snap_data->use_plane_axis_auto = RNA_boolean_get(&ptr, "plane_axis_auto"); } -static void preview_plane_cursor_free(void *customdata) +void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt) { - struct PlacementCursor *plc = customdata; + gzgt->name = "Placement Widget"; + gzgt->idname = view3d_gzgt_placement_id; - /* The window manager is freed first on exit. */ - wmWindowManager *wm = G_MAIN->wm.first; - if (UNLIKELY(wm != NULL)) { - WM_paint_cursor_end(plc->paintcursor); - } - MEM_freeN(plc); -} + gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; -static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup) -{ - BLI_assert(gzgroup->customdata == NULL); - struct PlacementCursor *plc = MEM_callocN(sizeof(*plc), __func__); - plc->gzgroup = gzgroup; - plc->paintcursor = WM_paint_cursor_activate( - SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw, plc); - gzgroup->customdata = plc; - gzgroup->customdata_free = preview_plane_cursor_free; - - preview_plane_cursor_visible_set(gzgroup, true); -} + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; -static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw) -{ - struct PlacementCursor *plc = gzgroup->customdata; - plc->do_draw = do_draw; + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_placement_setup; + gzgt->draw_prepare = WIDGETGROUP_placement_draw_prepare; } /** \} */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 2e1e8eb4ca4..7f27d5fb180 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -48,6 +48,7 @@ #include "ED_node.h" #include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" +#include "ED_view3d.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -247,7 +248,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) loc_cur = t->tsnap.snapPoint; } - ED_gizmotypes_snap_3d_draw_util( + ED_view3d_cursor_snap_draw_util( rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); GPU_depth_test(GPU_DEPTH_LESS_EQUAL); @@ -1243,7 +1244,7 @@ short snapObjectsTransform( TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3]) { float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global; - return ED_transform_snap_object_project_view3d_ex( + return ED_transform_snap_object_project_view3d( t->tsnap.object_context, t->depsgraph, t->region, @@ -1259,10 +1260,7 @@ short snapObjectsTransform( target, dist_px, r_loc, - r_no, - NULL, - NULL, - NULL); + r_no); } /** \} */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 5f9250e87f7..17326001a99 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -3020,7 +3020,8 @@ static short transform_snap_context_project_view3d_mixed_impl( float r_no[3], int *r_index, Object **r_ob, - float r_obmat[4][4]) + float r_obmat[4][4], + float r_face_nor[3]) { BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != @@ -3067,22 +3068,27 @@ static short transform_snap_context_project_view3d_mixed_impl( &ob_eval, obmat, NULL); + if (has_hit) { + if (r_face_nor) { + copy_v3_v3(r_face_nor, no); + } - if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) { - retval = SCE_SNAP_MODE_FACE; + if ((snap_to_flag & SCE_SNAP_MODE_FACE)) { + retval = SCE_SNAP_MODE_FACE; - copy_v3_v3(r_loc, loc); - if (r_no) { - copy_v3_v3(r_no, no); - } - if (r_ob) { - *r_ob = ob_eval; - } - if (r_obmat) { - copy_m4_m4(r_obmat, obmat); - } - if (r_index) { - *r_index = index; + copy_v3_v3(r_loc, loc); + if (r_no) { + copy_v3_v3(r_no, no); + } + if (r_ob) { + *r_ob = ob_eval; + } + if (r_obmat) { + copy_m4_m4(r_obmat, obmat); + } + if (r_index) { + *r_index = index; + } } } } @@ -3182,6 +3188,10 @@ static short transform_snap_context_project_view3d_mixed_impl( if (r_index) { *r_index = index; } + if (r_face_nor && !has_hit) { + /* Fallback. */ + copy_v3_v3(r_face_nor, no); + } *dist_px = dist_px_tmp; } @@ -3203,7 +3213,8 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, float r_no[3], int *r_index, Object **r_ob, - float r_obmat[4][4]) + float r_obmat[4][4], + float r_face_nor[3]) { return transform_snap_context_project_view3d_mixed_impl(sctx, depsgraph, @@ -3218,7 +3229,8 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, r_no, r_index, r_ob, - r_obmat); + r_obmat, + r_face_nor); } /** @@ -3259,6 +3271,7 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, r_no, NULL, NULL, + NULL, NULL) != 0; } -- cgit v1.2.3