diff options
author | Campbell Barton <ideasman42@gmail.com> | 2016-07-18 12:25:44 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2016-07-18 12:25:44 +0300 |
commit | 9186b9ae4806f4bbc1a14417c408e844f8e8cc1a (patch) | |
tree | 117bbd4ace75825e3a65f0ba2a447509bde0df85 /source/blender/editors | |
parent | cfbd605567f48229a923df382baf6db98fbafc61 (diff) | |
parent | 9946cca14676bf07b3c7c103e99033fe1e4e423e (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender/editors')
32 files changed, 1348 insertions, 820 deletions
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 6306926e0b2..6979a324b69 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -424,7 +424,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone for (curBone = bones->first; curBone; curBone = curBone->next) { eBone = MEM_callocN(sizeof(EditBone), "make_editbone"); - /* Copy relevant data from bone to eBone */ + /* Copy relevant data from bone to eBone + * Keep selection logic in sync with ED_armature_sync_selection. + */ eBone->parent = parent; BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name)); eBone->flag = curBone->flag; @@ -435,11 +437,11 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone eBone->flag |= BONE_TIPSEL; if (eBone->parent && (eBone->flag & BONE_CONNECTED)) { eBone->parent->flag |= BONE_TIPSEL; - eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */ - } - else { - eBone->flag |= BONE_ROOTSEL; } + + /* For connected bones, take care when changing the selection when we have a connected parent, + * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */ + eBone->flag |= BONE_ROOTSEL; } else { /* if the bone is not selected, but connected to its parent diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 81e2558e765..602e203a381 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -325,18 +325,18 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool /* Notes: * - All the defines for this (User-Pref settings and Per-Scene settings) * are defined in DNA_userdef_types.h - * - Scene settings take presidence over those for userprefs, with old files + * - Scene settings take precedence over those for userprefs, with old files * inheriting userpref settings for the scene settings * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored * as userprefs */ /* Auto-Keying macros for use by various tools */ -/* check if auto-keyframing is enabled (per scene takes presidence) */ +/* check if auto-keyframing is enabled (per scene takes precedence) */ #define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON)) -/* check the mode for auto-keyframing (per scene takes presidence) */ +/* check the mode for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode)) -/* check if a flag is set for auto-keyframing (per scene takes presidence) */ +/* check if a flag is set for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_FLAG(scene, flag) \ ((scene) ? \ ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index b09284aa759..48c1e2d1996 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -208,6 +208,7 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); +bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); bool ED_view3d_win_to_ray( const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip); @@ -218,6 +219,7 @@ void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coo void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]); void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); +void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index ba7240be5d8..cbe8654ceb6 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1138,7 +1138,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, * as new items are added to the menu later on. It also optimises efficiency - * a radial menu is best kept symmetrical, with as large an angle between * items as possible, so that the gestural mouse movements can be fast and inexact. - + * * It starts off with two opposite sides for the first two items * then joined by the one below for the third (this way, even with three items, * the menu seems to still be 'in order' reading left to right). Then the fourth is diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 0a0ecf93d17..11703208b2a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1057,7 +1057,9 @@ static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block) } } -static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data, const wmEvent *event) +static bool ui_multibut_states_tag( + uiBut *but_active, + uiHandleButtonData *data, const wmEvent *event) { uiBut *but; float seg[2][2]; @@ -1668,7 +1670,9 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent return BLI_rcti_isect_pt(&rect, x, y); } -static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static bool ui_but_drag_init( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { /* prevent other WM gestures to start while we try to drag */ WM_gestures_remove(C); @@ -1740,11 +1744,16 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, } } else { - wmDrag *drag; + wmDrag *drag = WM_event_start_drag( + C, but->icon, but->dragtype, but->dragpoin, + ui_but_value_get(but), WM_DRAG_NOP); - drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP); - if (but->imb) - WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)); + if (but->imb) { + WM_event_drag_image( + drag, but->imb, but->imb_scale, + BLI_rctf_size_x(&but->rect), + BLI_rctf_size_y(&but->rect)); + } } return true; } @@ -1872,11 +1881,15 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to) /* (3) add a new controller */ if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) { cont = (bController *)ob->controllers.last; - cont->type = CONT_LOGIC_AND; /* Quick fix to make sure we always have an AND controller. It might be nicer to make sure the operator gives us the right one though... */ + /* Quick fix to make sure we always have an AND controller. + * It might be nicer to make sure the operator gives us the right one though... */ + cont->type = CONT_LOGIC_AND; /* (4) link the sensor->controller->actuator */ tmp_but = MEM_callocN(sizeof(uiBut), "uiBut"); - UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin); + UI_but_link_set( + tmp_but, (void **)&cont, (void ***)&(cont->links), + &cont->totlinks, from->link->tocode, (int)to->hardmin); tmp_but->hardmin = from->link->tocode; tmp_but->poin = (char *)cont; @@ -3180,7 +3193,9 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } -static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int retval = WM_UI_HANDLER_CONTINUE; bool changed = false, inbox = false, update = false; @@ -3233,7 +3248,8 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle if (data->searchbox) inbox = ui_searchbox_inside(data->searchbox, event->x, event->y); - /* for double click: we do a press again for when you first click on button (selects all text, no cursor pos) */ + /* for double click: we do a press again for when you first click on button + * (selects all text, no cursor pos) */ if (event->val == KM_PRESS || event->val == KM_DBL_CLICK) { float mx, my; @@ -3477,7 +3493,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle ED_region_tag_redraw(data->region); } -static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit_select( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, retval = WM_UI_HANDLER_CONTINUE; @@ -3682,7 +3700,9 @@ static uiBut *ui_but_list_row_text_activate( /* ***************** events for different button types *************** */ -static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BUT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS) { @@ -3713,7 +3733,9 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HOTKEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3776,7 +3798,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_KEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3802,7 +3826,9 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TEX( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3830,7 +3856,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SEARCH_UNLINK( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { uiButExtraIconType extra_icon_type; @@ -3877,7 +3905,9 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa return ui_do_but_TEX(C, block, but, data, event); } -static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TOG( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { #ifdef USE_DRAG_TOGGLE if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -3944,7 +3974,9 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_EXIT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -4092,7 +4124,7 @@ static float ui_numedit_apply_snap( static bool ui_numedit_but_NUM( uiBut *but, uiHandleButtonData *data, - int mx, + int mx, const bool is_motion, const enum eSnapType snap, float fac) { float deler, tempf, softmin, softmax, softrange; @@ -4100,8 +4132,10 @@ static bool ui_numedit_but_NUM( bool changed = false; const bool is_float = ui_but_is_float(but); - /* prevent unwanted drag adjustments */ - if (ui_but_dragedit_update_mval(data, mx) == false) { + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ + if ((is_motion || data->draglock) && + (ui_but_dragedit_update_mval(data, mx) == false)) + { return changed; } @@ -4242,7 +4276,9 @@ static bool ui_numedit_but_NUM( return changed; } -static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_NUM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; /* mouse location scaled to fit the UI */ int screen_mx, screen_my; /* mouse location kept at screen pixel coords */ @@ -4324,6 +4360,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); const enum eSnapType snap = ui_event_to_snap(event); float fac; @@ -4335,8 +4372,9 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton fac = 1.0f; if (event->shift) fac /= 10.0f; - if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac)) + if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), is_motion, snap, fac)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) { @@ -4430,7 +4468,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton static bool ui_numedit_but_SLI( uiBut *but, uiHandleButtonData *data, - int mx, const bool is_horizontal, + int mx, const bool is_horizontal, const bool is_motion, const bool snap, const bool shift) { float deler, f, tempf, softmin, softmax, softrange; @@ -4440,8 +4478,9 @@ static bool ui_numedit_but_SLI( /* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */ float offs; - /* prevent unwanted drag adjustments */ + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ if ((but->type != UI_BTYPE_SCROLL) && + (is_motion || data->draglock) && (ui_but_dragedit_update_mval(data, mx) == false)) { return changed; @@ -4541,7 +4580,9 @@ static bool ui_numedit_but_SLI( return changed; } -static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SLI( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, click = 0; int retval = WM_UI_HANDLER_CONTINUE; @@ -4634,12 +4675,14 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); #ifdef USE_DRAG_MULTINUM data->multi_data.drag_dir[0] += abs(data->draglastx - mx); data->multi_data.drag_dir[1] += abs(data->draglasty - my); #endif - if (ui_numedit_but_SLI(but, data, mx, true, event->ctrl != 0, event->shift != 0)) + if (ui_numedit_but_SLI(but, data, mx, true, is_motion, event->ctrl != 0, event->shift != 0)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { @@ -4722,7 +4765,9 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return retval; } -static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SCROLL( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my /*, click = 0 */; int retval = WM_UI_HANDLER_CONTINUE; @@ -4765,8 +4810,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (event->type == MOUSEMOVE) { - if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, false, false)) + const bool is_motion = (event->type == MOUSEMOVE); + if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, is_motion, false, false)) { ui_numedit_apply(C, block, but, data); + } } retval = WM_UI_HANDLER_BREAK; @@ -4775,7 +4822,9 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } -static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_GRIP( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; int retval = WM_UI_HANDLER_CONTINUE; @@ -4826,7 +4875,9 @@ static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButto return retval; } -static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LISTROW( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* hack to pass on ctrl+click and double click to overlapping text @@ -4846,7 +4897,9 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, return ui_do_but_EXIT(C, but, data, event); } -static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BLOCK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -5021,7 +5074,9 @@ static void ui_palette_set_active(uiBut *but) } } -static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLOR( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* first handle click on icondrag type button */ @@ -5154,7 +5209,9 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_UNITVEC( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5431,7 +5488,9 @@ static void ui_ndofedit_but_HSVCUBE( ui_but_v3_set(but, data->vec); } -static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCUBE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5693,7 +5752,9 @@ static void ui_ndofedit_but_HSVCIRCLE( } -static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCIRCLE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorPicker *cpicker = but->custom_data; float *hsv = cpicker->color_data; @@ -5821,7 +5882,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLORBAND( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorBand *coba; CBData *cbd; @@ -5997,7 +6060,9 @@ static bool ui_numedit_but_CURVE( return changed; } -static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_CURVE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, a; bool changed = false; @@ -6165,7 +6230,9 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HISTOGRAM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6238,7 +6305,9 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx return changed; } -static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_WAVEFORM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6292,7 +6361,9 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LINK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { VECCOPY2D(but->linkto, event->mval); @@ -6355,7 +6426,9 @@ static bool ui_numedit_but_TRACKPREVIEW( return changed; } -static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TRACKPREVIEW( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6851,7 +6924,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); RNA_string_set(&ptr_props, "doc_id", buf); - uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), + uiItemFullO(layout, "WM_OT_doc_view", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); /* XXX inactive option, not for public! */ @@ -6860,7 +6934,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) RNA_string_set(&ptr_props, "doc_id", buf); RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop)); - uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(layout, "WM_OT_doc_edit", + "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); #endif } } @@ -7440,7 +7515,8 @@ static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y) /** * Can we mouse over the button or is it hidden/disabled/layout. - * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. + * \note ctrl is kind of a hack currently, + * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. */ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit) { @@ -7634,7 +7710,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if (but->block->auto_open == true) { /* test for toolbox */ time = 1; } - else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) { + else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || + (but->block->auto_open == true)) + { time = 5 * U.menuthreshold2; } else if (U.uiflag & USER_MENUOPENAUTO) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index c1d7a9ada96..3660160a98c 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1061,6 +1061,9 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) } } +static void ui_id_preview_image_render_size( + const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job); + void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big) { Icon *icon = BKE_icon_get(icon_id); @@ -1076,22 +1079,19 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi } if (di) { - if (di->type == ICON_TYPE_PREVIEW) { - PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj; - - if (prv) { - const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; - - if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) { - return; + switch (di->type) { + case ICON_TYPE_PREVIEW: + { + ID *id = (icon->type != 0) ? icon->obj : NULL; + PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj; + + if (prv) { + const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; + + if (id || prv->use_deferred) { + ui_id_preview_image_render_size(C, NULL, id, prv, size, true); + } } - - icon_create_rect(prv, size); - - /* Always using job (background) version. */ - ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]); - - prv->flag[size] &= ~PRV_CHANGED; } } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 01b10b7b032..1af6d902b18 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -416,7 +416,7 @@ bool UI_context_copy_to_selected_list( if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || - ID_IS_LINKED_DATABLOCK(id_data->lib) || + ID_IS_LINKED_DATABLOCK(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 575b32e81e8..d4205c50ddc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -110,7 +110,7 @@ bool ui_but_menu_step_poll(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_MENU); - /* currenly only RNA buttons */ + /* currently only RNA buttons */ return ((but->menu_step_func != NULL) || (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM)); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 7cc7b540cc0..3af25ba8894 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -301,7 +301,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - if (id_make_local(CTX_data_main(C), id, false)) { + if (id_make_local(CTX_data_main(C), id, false, false)) { /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); @@ -453,7 +453,7 @@ static void template_ID( else { but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local")); - if (!id_make_local(CTX_data_main(C), id, true /* test */) || (idfrom && idfrom->lib)) + if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)) UI_but_flag_enable(but, UI_BUT_DISABLED); } diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 69588928253..281a8b2a02d 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -563,7 +563,7 @@ static BMEdge *bm_face_split_edge_find( if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || BM_edge_exists(v_pivot, l_iter->e->v2))) { - /* very unlikley but will cause complications splicing the verts together, + /* very unlikely but will cause complications splicing the verts together, * so just skip this case */ ok = false; } diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index e3e5863dc0e..2cdb00286aa 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -395,7 +395,7 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, * return an un-ordered array of loop pairs * use for rebuilding face-fill * - * \note the method currenly used fails for edges with 3+ face users and gives + * \note the method currently used fails for edges with 3+ face users and gives * nasty holes in the mesh, there isnt a good way of knowing ahead of time * which loops will be split apart (its possible to figure out but quite involved). * So for now this is a known limitation of current rip-fill option. diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index bcdd170c53c..0fe43c44d7d 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -440,7 +440,7 @@ static int group_link_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; /* Early return check, if the object is already in group - * we could sckip all the dependency check and just consider + * we could skip all the dependency check and just consider * operator is finished. */ if (BKE_group_object_exists(group, ob)) { diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 55eb30ac2de..d8b0767562c 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2103,11 +2103,11 @@ static void make_local_makelocalmaterial(Material *ma) AnimData *adt; int b; - id_make_local(G.main, &ma->id, false); + id_make_local(G.main, &ma->id, false, false); for (b = 0; b < MAX_MTEX; b++) if (ma->mtex[b] && ma->mtex[b]->tex) - id_make_local(G.main, &ma->mtex[b]->tex->id, false); + id_make_local(G.main, &ma->mtex[b]->tex->id, false, false); adt = BKE_animdata_from_id(&ma->id); if (adt) BKE_animdata_make_local(adt); @@ -2235,7 +2235,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } if (ob->id.lib) - id_make_local(bmain, &ob->id, false); + id_make_local(bmain, &ob->id, false, false); } CTX_DATA_END; @@ -2257,7 +2257,7 @@ static int make_local_exec(bContext *C, wmOperator *op) id = ob->data; if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) { - id_make_local(bmain, id, false); + id_make_local(bmain, id, false, false); adt = BKE_animdata_from_id(id); if (adt) BKE_animdata_make_local(adt); @@ -2289,7 +2289,7 @@ static int make_local_exec(bContext *C, wmOperator *op) for (b = 0; b < MAX_MTEX; b++) if (la->mtex[b] && la->mtex[b]->tex) - id_make_local(bmain, &la->mtex[b]->tex->id, false); + id_make_local(bmain, &la->mtex[b]->tex->id, false, false); } else { for (a = 0; a < ob->totcol; a++) { diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 8501cea4e00..7db32957b42 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -538,7 +538,6 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel /* can be NULL if parent in other scene */ if (baspar && BASE_SELECTABLE(v3d, baspar)) { - ED_base_object_select(basact, BA_DESELECT); ED_base_object_select(baspar, BA_SELECT); ED_base_object_activate(C, baspar); changed = true; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 6e8aaebcccc..ad41fb23a69 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3538,8 +3538,10 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) return BLI_natstrcmp(def_a->name, def_b->name); } -/* Sorts the weight groups according to the bone hierarchy of the - associated armature (similar to how bones are ordered in the Outliner) */ +/** + * Sorts the weight groups according to the bone hierarchy of the + * associated armature (similar to how bones are ordered in the Outliner) + */ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { if (bonebase == NULL) { diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 1203889cf0e..8c5d25ad44d 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -1482,7 +1482,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) void render_view3d_update(RenderEngine *engine, const bContext *C) { /* this shouldn't be needed and causes too many database rebuilds, but we - * aren't actually tracking updates for all relevent datablocks so this is + * aren't actually tracking updates for all relevant datablocks so this is * a catch-all for updates */ engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 6ed969cb270..d60c8e8dbd9 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -183,8 +183,8 @@ BLI_INLINE unsigned char f_to_char(const float val) /* to avoid locking in tile initialization */ #define TILE_PENDING SET_INT_IN_POINTER(-1) -/* This is mainly a convenience struct used so we can keep an array of images we use - * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread +/* This is mainly a convenience struct used so we can keep an array of images we use - + * their imbufs, etc, in 1 array, When using threads this array is copied for each thread * because 'partRedrawRect' and 'touch' values would not be thread safe */ typedef struct ProjPaintImage { Image *ima; @@ -202,7 +202,7 @@ typedef struct ProjPaintImage { */ typedef struct ProjStrokeHandle { /* Support for painting from multiple views at once, - * currently used to impliment symmetry painting, + * currently used to implement symmetry painting, * we can assume at least the first is set while painting. */ struct ProjPaintState *ps_views[8]; int ps_views_tot; @@ -2174,7 +2174,7 @@ static void project_bucket_clip_face( if ((*tot) < 3) { /* no intersections to speak of, but more probable is that all face is just outside the - * rectangle and culled due to float precision issues. Since above teste have failed, + * rectangle and culled due to float precision issues. Since above tests have failed, * just dump triangle as is for painting */ *tot = 0; copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index aa17cb02fe5..1431958501d 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -491,31 +491,30 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ -static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure, - const PaintSample *sample, PaintMode mode) +static bool paint_smooth_stroke( + PaintStroke *stroke, const PaintSample *sample, PaintMode mode, + float r_mouse[2], float *r_pressure) { if (paint_supports_smooth_stroke(stroke->brush, mode)) { float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; - float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; - float dx = stroke->last_mouse_position[0] - sample->mouse[0]; - float dy = stroke->last_mouse_position[1] - sample->mouse[1]; + float u = stroke->brush->smooth_stroke_factor; /* If the mouse is moving within the radius of the last move, * don't update the mouse position. This allows sharp turns. */ - if (dx * dx + dy * dy < radius * radius) - return 0; + if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) { + return false; + } - output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u; - output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u; - *outpressure = sample->pressure * v + stroke->last_pressure * u; + interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u); + *r_pressure = interpf(sample->pressure, stroke->last_pressure, u); } else { - output[0] = sample->mouse[0]; - output[1] = sample->mouse[1]; - *outpressure = sample->pressure; + r_mouse[0] = sample->mouse[0]; + r_mouse[1] = sample->mouse[1]; + *r_pressure = sample->pressure; } - return 1; + return true; } static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure) @@ -1190,7 +1189,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* airbrush */ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { - if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) { + if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) { if (stroke->stroke_started) { if (paint_space_stroke_enabled(br, mode)) { if (paint_space_stroke(C, op, mouse, pressure)) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index e874a969963..f21f62cc141 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2379,9 +2379,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(vc->rv3d->persmat, mat); /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); @@ -2842,9 +2841,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index cc7531b9783..1305b76b5ad 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1145,7 +1145,9 @@ static void calc_area_normal_and_center( /* Return modified brush strength. Includes the direction of the brush, positive * values pull vertices, negative values push. Uses tablet pressure and a * special multiplier found experimentally to scale the strength factor. */ -static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups) +static float brush_strength( + const Sculpt *sd, const StrokeCache *cache, + const float feather, const UnifiedPaintSettings *ups) { const Scene *scene = cache->vc->scene; const Brush *brush = BKE_paint_brush((Paint *)&sd->paint); @@ -3985,7 +3987,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) } /* Initialize the stroke cache invariants from operator properties */ -static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) +static void sculpt_update_cache_invariants( + bContext *C, Sculpt *sd, SculptSession *ss, + wmOperator *op, const float mouse[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); Scene *scene = CTX_data_scene(C); @@ -4448,7 +4452,9 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin) } } -static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original) +static float sculpt_raycast_init( + ViewContext *vc, const float mouse[2], + float ray_start[3], float ray_end[3], float ray_normal[3], bool original) { float obimat[4][4]; float dist; @@ -4956,8 +4962,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id); } - ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); + ss->cd_vert_node_offset = CustomData_get_n_offset( + &ss->bm->vdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; @@ -4967,8 +4974,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id); } - ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); + ss->cd_face_node_offset = CustomData_get_n_offset( + &ss->bm->pdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; } @@ -5667,7 +5675,8 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); + RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 1ff656243d6..14d0f909d23 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -634,7 +634,7 @@ typedef struct PrefetchQueue { short render_size, render_flag; /* If true prefecthing goes forward in time, - * othwewise it goes backwards in time (starting from current frame). + * otherwise it goes backwards in time (starting from current frame). */ bool forward; diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index b837e516422..ae91a466495 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -826,7 +826,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) //if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0) // return; - /* No curve to modify/visualise the result? + /* No curve to modify/visualize the result? * => We still want to show the 1-1 default... */ if ((fcu->totvert == 0) && BLI_listbase_is_empty(&fcu->modifiers)) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 06caf930988..1538842b139 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1061,6 +1061,12 @@ typedef struct ImageOpenData { ImageFormatData im_format; } ImageOpenData; +typedef struct ImageFrameRange { + struct ImageFrameRange *next, *prev; + ListBase frames; + char filepath[FILE_MAX]; +} ImageFrameRange; + typedef struct ImageFrame { struct ImageFrame *next, *prev; int framenr; @@ -1086,10 +1092,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op) * \param frames [out] the list of frame numbers found in the files matching the first one by name * \param path [out] the full path of the first file in the list of image files */ -static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen) +static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all) { char dir[FILE_MAXDIR]; - bool is_first_entry = true; + ImageFrameRange *frame_range = NULL; RNA_string_get(ptr, "directory", dir); RNA_BEGIN (ptr, itemptr, "files") @@ -1101,29 +1107,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); /* use the first file in the list as base filename */ - if (is_first_entry) { - BLI_join_dirfile(path, maxlen, dir, filename); - frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits); - BLI_addtail(frames, frame); - is_first_entry = false; + frame->framenr = BLI_stringdec(filename, head, tail, &digits); + + /* still in the same sequence */ + if ((frame_range != NULL) && + (STREQLEN(base_head, head, FILE_MAX)) && + (STREQLEN(base_tail, tail, FILE_MAX))) + { + /* pass */ } else { - frame->framenr = BLI_stringdec(filename, head, tail, &digits); + /* start a new frame range */ + frame_range = MEM_callocN(sizeof(*frame_range), __func__); + BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename); + BLI_addtail(frames_all, frame_range); - /* still in the same sequence */ - if ((STREQLEN(base_head, head, FILE_MAX)) && - (STREQLEN(base_tail, tail, FILE_MAX))) - { - BLI_addtail(frames, frame); - } - else { - /* different file base name found, is ignored */ - MEM_freeN(filename); - MEM_freeN(frame); - break; - } + BLI_strncpy(base_head, head, sizeof(base_head)); + BLI_strncpy(base_tail, tail, sizeof(base_tail)); } + BLI_addtail(&frame_range->frames, frame); MEM_freeN(filename); } RNA_END @@ -1164,6 +1167,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs) return 0; } +static Image *image_open_single( + wmOperator *op, const char *filepath, const char *relbase, + bool is_relative_path, bool use_multiview, int frame_seq_len) +{ + bool exists = false; + Image *ima = NULL; + + errno = 0; + ima = BKE_image_load_exists_ex(filepath, &exists); + + if (!ima) { + if (op->customdata) MEM_freeN(op->customdata); + BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", + filepath, errno ? strerror(errno) : TIP_("unsupported image format")); + return NULL; + } + + if (!exists) { + /* only image path after save, never ibuf */ + if (is_relative_path) { + BLI_path_rel(ima->name, relbase); + } + + /* handle multiview images */ + if (use_multiview) { + ImageOpenData *iod = op->customdata; + ImageFormatData *imf = &iod->im_format; + + ima->flag |= IMA_USE_VIEWS; + ima->views_format = imf->views_format; + *ima->stereo3d_format = imf->stereo3d_format; + } + else { + ima->flag &= ~IMA_USE_VIEWS; + BKE_image_free_views(ima); + } + + if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) { + ima->source = IMA_SRC_SEQUENCE; + } + } + + return ima; +} + + static int image_open_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -1174,70 +1223,60 @@ static int image_open_exec(bContext *C, wmOperator *op) ImageOpenData *iod = op->customdata; PointerRNA idptr; Image *ima = NULL; - char path[FILE_MAX]; + char filepath[FILE_MAX]; int frame_seq_len = 0; int frame_ofs = 1; - bool exists = false; const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); + const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview"); - RNA_string_get(op->ptr, "filepath", path); + if (!op->customdata) + image_open_init(C, op); + + RNA_string_get(op->ptr, "filepath", filepath); if (RNA_struct_property_is_set(op->ptr, "directory") && RNA_struct_property_is_set(op->ptr, "files")) { - /* only to pass to imbuf */ - char path_full[FILE_MAX]; - BLI_strncpy(path_full, path, sizeof(path_full)); - BLI_path_abs(path_full, G.main->name); + bool was_relative = BLI_path_is_rel(filepath); + ListBase frame_ranges_all; - if (!IMB_isanim(path_full)) { - bool was_relative = BLI_path_is_rel(path); - ListBase frames; + BLI_listbase_clear(&frame_ranges_all); + image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all); + for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) { + int frame_range_ofs; + int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs); + BLI_freelistN(&frame_range->frames); - BLI_listbase_clear(&frames); - image_sequence_get_frames(op->ptr, &frames, path, sizeof(path)); - frame_seq_len = image_sequence_get_len(&frames, &frame_ofs); - BLI_freelistN(&frames); + char filepath_range[FILE_MAX]; + BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range)); if (was_relative) { - BLI_path_rel(path, G.main->name); + BLI_path_rel(filepath_range, bmain->name); } - } - } - - errno = 0; - ima = BKE_image_load_exists_ex(path, &exists); + Image *ima_range = image_open_single( + op, filepath_range, bmain->name, + is_relative_path, use_multiview, frame_range_seq_len); - if (!ima) { - if (op->customdata) MEM_freeN(op->customdata); - BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", - path, errno ? strerror(errno) : TIP_("unsupported image format")); - return OPERATOR_CANCELLED; - } - - if (!op->customdata) - image_open_init(C, op); - - /* handle multiview images */ - if (RNA_boolean_get(op->ptr, "use_multiview")) { - ImageFormatData *imf = &iod->im_format; - - ima->flag |= IMA_USE_VIEWS; - ima->views_format = imf->views_format; - *ima->stereo3d_format = imf->stereo3d_format; + /* take the first image */ + if ((ima == NULL) && ima_range) { + ima = ima_range; + frame_seq_len = frame_range_seq_len; + frame_ofs = frame_range_ofs; + } + } + BLI_freelistN(&frame_ranges_all); } else { - ima->flag &= ~IMA_USE_VIEWS; - BKE_image_free_views(ima); + /* for drag & drop etc. */ + ima = image_open_single( + op, filepath, bmain->name, + is_relative_path, use_multiview, 1); } - /* only image path after save, never ibuf */ - if (is_relative_path) { - if (!exists) { - BLI_path_rel(ima->name, bmain->name); - } + if (ima == NULL) { + return OPERATOR_CANCELLED; } /* hook into UI */ @@ -1245,11 +1284,8 @@ static int image_open_exec(bContext *C, wmOperator *op) if (iod->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer also increases user, so this compensates it */ id_us_min(&ima->id); - if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) { - ima->source = IMA_SRC_SEQUENCE; - } RNA_id_pointer_create(&ima->id, &idptr); RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 7b7ea180604..14efd4338b4 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1234,106 +1234,106 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_DOT); break; } } - else if (GS(tselem->id->name) == ID_OB) { - Object *ob = (Object *)tselem->id; - switch (ob->type) { - case OB_LAMP: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break; - case OB_MESH: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break; - case OB_CAMERA: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break; - case OB_CURVE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break; - case OB_MBALL: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break; - case OB_LATTICE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break; - case OB_ARMATURE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break; - case OB_FONT: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break; - case OB_SURF: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break; - case OB_SPEAKER: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break; - case OB_EMPTY: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break; - + else if (tselem->id) { + if (GS(tselem->id->name) == ID_OB) { + Object *ob = (Object *)tselem->id; + switch (ob->type) { + case OB_LAMP: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break; + case OB_MESH: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break; + case OB_CAMERA: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break; + case OB_CURVE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break; + case OB_MBALL: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break; + case OB_LATTICE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break; + case OB_ARMATURE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break; + case OB_FONT: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break; + case OB_SURF: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break; + case OB_SPEAKER: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break; + case OB_EMPTY: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break; + } } - } - else { - switch (GS(tselem->id->name)) { - case ID_SCE: - tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; - case ID_ME: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break; - case ID_CU: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break; - case ID_MB: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break; - case ID_LT: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break; - case ID_LA: - { - Lamp *la = (Lamp *)tselem->id; - - switch (la->type) { - case LA_LOCAL: - tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break; - case LA_SUN: - tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break; - case LA_SPOT: - tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break; - case LA_HEMI: - tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break; - case LA_AREA: - tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break; - default: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break; + else { + switch (GS(tselem->id->name)) { + case ID_SCE: + tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; + case ID_ME: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break; + case ID_CU: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break; + case ID_MB: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break; + case ID_LT: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break; + case ID_LA: + { + Lamp *la = (Lamp *)tselem->id; + switch (la->type) { + case LA_LOCAL: + tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break; + case LA_SUN: + tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break; + case LA_SPOT: + tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break; + case LA_HEMI: + tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break; + case LA_AREA: + tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break; + default: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break; + } + break; } - break; + case ID_MA: + tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break; + case ID_TE: + tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break; + case ID_IM: + tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break; + case ID_SPK: + case ID_SO: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break; + case ID_AR: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break; + case ID_CA: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break; + case ID_KE: + tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break; + case ID_WO: + tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break; + case ID_AC: + tselem_draw_icon_uibut(&arg, ICON_ACTION); break; + case ID_NLA: + tselem_draw_icon_uibut(&arg, ICON_NLA); break; + case ID_TXT: + tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break; + case ID_GR: + tselem_draw_icon_uibut(&arg, ICON_GROUP); break; + case ID_LI: + if (tselem->id->tag & LIB_TAG_MISSING) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); + } + else if (((Library *)tselem->id)->parent) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); + } + else { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); + } + break; + case ID_LS: + tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; + case ID_GD: + tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; } - case ID_MA: - tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break; - case ID_TE: - tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break; - case ID_IM: - tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break; - case ID_SPK: - case ID_SO: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break; - case ID_AR: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break; - case ID_CA: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break; - case ID_KE: - tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break; - case ID_WO: - tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break; - case ID_AC: - tselem_draw_icon_uibut(&arg, ICON_ACTION); break; - case ID_NLA: - tselem_draw_icon_uibut(&arg, ICON_NLA); break; - case ID_TXT: - tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break; - case ID_GR: - tselem_draw_icon_uibut(&arg, ICON_GROUP); break; - case ID_LI: - if (tselem->id->tag & LIB_TAG_MISSING) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); - } - else if (((Library *)tselem->id)->parent) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); - } - else { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); - } - break; - case ID_LS: - tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; - case ID_GD: - tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; } } } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index f3235d07757..111e60e5159 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -439,7 +439,7 @@ static void id_local_cb( Main *bmain = CTX_data_main(C); /* if the ID type has no special local function, * just clear the lib */ - if (id_make_local(bmain, tselem->id, false) == false) { + if (id_make_local(bmain, tselem->id, false, false) == false) { id_clear_lib_data(bmain, tselem->id); } } @@ -516,23 +516,16 @@ static void group_linkobs2scene_cb( Group *group = (Group *)tselem->id; GroupObject *gob; Base *base; - + for (gob = group->gobject.first; gob; gob = gob->next) { base = BKE_scene_base_find(scene, gob->ob); - if (base) { - base->object->flag |= SELECT; - base->flag |= SELECT; - } - else { + if (!base) { /* link to scene */ - base = MEM_callocN(sizeof(Base), "add_base"); - BLI_addhead(&scene->base, base); - base->lay = gob->ob->lay; - gob->ob->flag |= SELECT; - base->flag = gob->ob->flag; - base->object = gob->ob; + base = BKE_scene_base_add(scene, gob->ob); id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */ } + base->object->flag |= SELECT; + base->flag |= SELECT; } } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index c11a4d2e5a3..ede6b7ce469 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -1071,7 +1071,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const { bool is_type_set = RNA_struct_property_is_set(op->ptr, "type"); int type = -1; - int prop_flag = SEQPROP_ENDFRAME; + int prop_flag = SEQPROP_ENDFRAME | SEQPROP_NOPATHS; if (is_type_set) { type = RNA_enum_get(op->ptr, "type"); @@ -1106,9 +1106,6 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel( - ot, 0, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color", diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 2b0bd7690e2..83fde34fcde 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3075,7 +3075,9 @@ static int viewselected_exec(bContext *C, wmOperator *op) else if (BKE_paint_select_face_test(ob)) { ok = paintface_minmax(ob, min, max); } - else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) { + else if (ob && + (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) + { BKE_paint_stroke_get_average(scene, ob, min); copy_v3_v3(max, min); ok = true; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 2d050c4fa95..c5026fbb32b 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -274,6 +274,7 @@ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]); void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot); +void VIEW3D_OT_snap_selected_to_active(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1c84ce3c985..b273f46fca3 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -214,6 +214,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid); WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor); + WM_operatortype_append(VIEW3D_OT_snap_selected_to_active); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index ac05853e6d0..7448d4c658e 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -312,25 +312,9 @@ static void view3d_win_to_ray_segment( if (!r_ray_co) r_ray_co = _ray_co; if (!r_ray_dir) r_ray_dir = _ray_dir; + ED_view3d_win_to_origin(ar, mval, r_ray_co); ED_view3d_win_to_vector(ar, mval, r_ray_dir); - if (rv3d->is_persp) { - copy_v3_v3(r_ray_co, rv3d->viewinv[3]); - } - else { - r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f; - r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f; - - if (rv3d->persp == RV3D_CAMOB) { - r_ray_co[2] = -1.0f; - } - else { - r_ray_co[2] = 0.0f; - } - - mul_project_m4_v3(rv3d->persinv, r_ray_co); - } - if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) { end_offset = v3d->far / 2.0f; start_offset = -end_offset; @@ -347,7 +331,7 @@ static void view3d_win_to_ray_segment( } } -BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) +bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) { if ((rv3d->rflag & RV3D_CLIPPING) && (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6, @@ -384,7 +368,7 @@ bool ED_view3d_win_to_ray_ex( /* bounds clipping */ if (do_clip) { - return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); + return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); } return true; @@ -549,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3] } /** + * Calculate a 3d origin from 2d window coordinates. + * \note Orthographic views have a less obvious origin, + * Since far clip can be a very large value resulting in numeric precision issues, + * the origin in this case is close to zero coordinate. + * + * \param ar The region (used for the window width and height). + * \param mval The area relative 2d location (such as event->mval converted to floats). + * \param out The resulting normalized world-space direction vector. + */ +void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3]) +{ + RegionView3D *rv3d = ar->regiondata; + if (rv3d->is_persp) { + copy_v3_v3(out, rv3d->viewinv[3]); + } + else { + out[0] = 2.0f * mval[0] / ar->winx - 1.0f; + out[1] = 2.0f * mval[1] / ar->winy - 1.0f; + + if (rv3d->persp == RV3D_CAMOB) { + out[2] = -1.0f; + } + else { + out[2] = 0.0f; + } + + mul_project_m4_v3(rv3d->persinv, out); + } +} + +/** * Calculate a 3d direction vector from 2d window coordinates. * This direction vector starts and the view in the direction of the 2d window coordinates. * In orthographic view all window coordinates yield the same vector. @@ -599,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2 /* bounds clipping */ if (do_clip) { - return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); + return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); } return true; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index e8e7d3c62fb..5dd69cc66eb 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -44,6 +44,7 @@ #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_object.h" +#include "BKE_report.h" #include "BKE_tracking.h" #include "WM_api.h" @@ -204,7 +205,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) /* *************************************************** */ -static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) +static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -213,15 +214,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) TransVertStore tvs = {NULL}; TransVert *tv; float imat[3][3], bmat[3][3]; - const float *cursor_global; float center_global[3]; float offset_global[3]; int a; - const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); - - cursor_global = ED_view3d_cursor3d_get(scene, v3d); - if (use_offset) { if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) @@ -231,11 +227,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { snap_curs_to_sel_ex(C, center_global); } - sub_v3_v3v3(offset_global, cursor_global, center_global); + sub_v3_v3v3(offset_global, snap_target_global, center_global); } if (obedit) { - float cursor_local[3]; + float snap_target_local[3]; if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, 0); @@ -246,8 +242,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) invert_m3_m3(imat, bmat); /* get the cursor in object space */ - sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]); - mul_m3_v3(imat, cursor_local); + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + mul_m3_v3(imat, snap_target_local); if (use_offset) { float offset_local[3]; @@ -262,7 +258,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(tv->loc, cursor_local); + copy_v3_v3(tv->loc, snap_target_local); } } @@ -274,10 +270,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) bPoseChannel *pchan; bArmature *arm = obact->data; - float cursor_local[3]; + float snap_target_local[3]; invert_m4_m4(obact->imat, obact->obmat); - mul_v3_m4v3(cursor_local, obact->imat, cursor_global); + mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global); for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if ((pchan->bone->flag & BONE_SELECTED) && @@ -311,7 +307,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); } else { - BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose); + BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); } /* copy new position */ @@ -367,7 +363,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); } else { - copy_v3_v3(cursor_parent, cursor_global); + copy_v3_v3(cursor_parent, snap_target_global); } sub_v3_v3(cursor_parent, ob->obmat[3]); @@ -401,6 +397,18 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op) +{ + const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); + + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + + const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d); + + return snap_selected_to_location(C, snap_target_global, use_offset); +} + void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) { /* identifiers */ @@ -409,7 +417,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) ot->idname = "VIEW3D_OT_snap_selected_to_cursor"; /* api callbacks */ - ot->exec = snap_sel_to_curs_exec; + ot->exec = snap_selected_to_cursor_exec; ot->poll = ED_operator_view3d_active; /* flags */ @@ -419,6 +427,34 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", ""); } +static int snap_selected_to_active_exec(bContext *C, wmOperator *op) +{ + float snap_target_global[3]; + + if (snap_calc_active_center(C, false, snap_target_global) == false) { + BKE_report(op->reports, RPT_ERROR, "No active element found!"); + return OPERATOR_CANCELLED; + } + + return snap_selected_to_location(C, snap_target_global, false); +} + +void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Snap Selection to Active"; + ot->description = "Snap selected item(s) to the active item"; + ot->idname = "VIEW3D_OT_snap_selected_to_active"; + + /* api callbacks */ + ot->exec = snap_selected_to_active_exec; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + /* *************************************************** */ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index ed6d49da681..724eba160a0 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -110,6 +110,12 @@ struct SnapObjectContext { }; +enum eViewProj { + VIEW_PROJ_NONE = -1, + VIEW_PROJ_ORTHO = 0, + VIEW_PROJ_PERSP = -1, +}; + static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); @@ -137,10 +143,6 @@ struct RayCastAll_Data { Object *ob; unsigned int ob_uuid; - /* DerivedMesh only */ - DerivedMesh *dm; - const struct MLoopTri *dm_looptri; - /* output data */ ListBase *hit_list; bool retval; @@ -218,76 +220,177 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH /* -------------------------------------------------------------------- */ -/** \name Internal Object Snapping API +/** \Common utilities * \{ */ + +/** + * Struct that kepts basic information about a BVHTree build from a editmesh. + */ +typedef struct BVHTreeFromMeshType { + void *userdata; + char type; +} BVHTreeFromMeshType; + +typedef struct PreDefProject { + float pmat[4][4]; /* perspective matrix multiplied by object matrix */ + float win_half[2]; + float dist_px_sq; +} PreDefProject; + +static void precalc_project( + PreDefProject *projectdefs, const ARegion *ar, + const float dist_px, float obmat[4][4]) +{ + float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat; + if (obmat) { + mul_m4_m4m4(projectdefs->pmat, pmat, obmat); + } + else { + copy_m4_m4(projectdefs->pmat, pmat); + } + projectdefs->win_half[0] = ar->winx / 2; + projectdefs->win_half[1] = ar->winy / 2; + projectdefs->dist_px_sq = SQUARE(dist_px); +} + +/** + * From a threshold (maximum distance to snap in pixels) returns: + * + * - The *real* distance (3D) if you are in orthographic-view. + * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. + */ +static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) +{ + const RegionView3D *rv3d = ar->regiondata; + if (ar->winx >= ar->winy) + return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; + else + return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; +} + +static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + return vert[index].co; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + return eve->co; + } + } + return NULL; +} + +static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + normal_short_to_float_v3(r_no, vert->no); + break; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + copy_v3_v3(r_no, eve->no); + break; + } + } +} + +static void get_edge_verts( + const BVHTreeFromMeshType *meshdata, const int index, + const float *v_pair[2]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + + const MVert *vert = data->vert; + const MEdge *edge = data->edge + index; + + v_pair[0] = vert[edge->v1].co; + v_pair[1] = vert[edge->v2].co; + break; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMEdge *eed = BM_edge_at_index(data->em->bm, index); + + v_pair[0] = eed->v1->co; + v_pair[1] = eed->v2->co; + break; + } + } +} + #define V3_MUL_ELEM(a, b) \ (a)[0] * (b)[0], \ (a)[1] * (b)[1], \ (a)[2] * (b)[2] -static bool test_vert( - const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3], - const float ray_depth_range[2], const float scale[3], const bool is_persp, +static bool test_vert_dist( + const float vco[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], /* read/write args */ float *ray_depth, float *dist_to_ray_sq, /* return args */ - float r_co[3], float r_no[3]) + float r_co[3]) { const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)}; - const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; - float depth; - float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth); + float depth, dist_sq; + dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth); if (depth < ray_depth_range[0]) { return false; } - if (is_persp) { - dist_sq /= SQUARE(depth); - } - if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { *dist_to_ray_sq = dist_sq; copy_v3_v3(r_co, vco); - if (vno) { - copy_v3_v3(r_no, vno); - } - *ray_depth = depth; return true; } return false; } -static bool test_edge( +static bool test_edge_dist( const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3], - const float ray_depth_range[2], const float scale[3], const bool is_persp, + const float ray_depth_range[2], const float scale[3], /* read/write args */ float *ray_depth, float *dist_to_ray_sq, /* return args */ - float r_co[3], float r_no[3]) + float r_co[3]) { const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)}; const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)}; const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; - float tmp_co[3], depth; - float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); + float tmp_co[3], depth, dist_sq; + dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); if (depth < ray_depth_range[0]) { return false; } - if (is_persp) { - dist_sq /= SQUARE(depth); - } - if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { *dist_to_ray_sq = dist_sq; @@ -297,10 +400,6 @@ static bool test_edge( copy_v3_v3(r_co, tmp_co); - if (r_no) { - sub_v3_v3v3(r_no, v1, v2); - } - *ray_depth = depth; return true; } @@ -309,50 +408,369 @@ static bool test_edge( #undef V3_MUL_ELEM +static bool test_projected_vert_dist( + PreDefProject *projectdefs, + const float co[3], const enum eViewProj view_proj, + const float mval[2], const float depth_range[2], + float r_co[3]) +{ + float depth; + float(*pmat)[4] = projectdefs->pmat; + if (view_proj == VIEW_PROJ_PERSP) { + depth = mul_project_m4_v3_zfac(pmat, co); + if (depth < depth_range[0] || depth > depth_range[1]) { + return false; + } + } + + float co2d[2] = { + (dot_m4_v3_row_x(pmat, co) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, co) + pmat[3][1]), + }; + + if (view_proj == VIEW_PROJ_PERSP) { + mul_v2_fl(co2d, 1 / depth); + } + + co2d[0] += 1.0f; + co2d[1] += 1.0f; + co2d[0] *= projectdefs->win_half[0]; + co2d[1] *= projectdefs->win_half[1]; + + const float dist_sq = len_squared_v2v2(mval, co2d); + if (dist_sq < projectdefs->dist_px_sq) { + copy_v3_v3(r_co, co); + projectdefs->dist_px_sq = dist_sq; + return true; + } + return false; +} + +static bool test_projected_edge_dist( + PreDefProject *projectdefs, + const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3], + const enum eViewProj view_proj, const float mval[2], const float depth_range[2], + float r_co[3]) +{ + + float tmp_co[3], depth; + dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth); + return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \Walk DFS + * \{ */ +typedef struct Object_Nearest2dPrecalc { + float ray_origin_local[3]; + float ray_direction_local[3]; + float ray_inv_dir[3]; + + PreDefProject projectdefs; + float mval[2]; + bool sign[3]; + bool r_axis_closest[3]; + float depth_range[2]; + + void *userdata; + int index; + float co[3]; + float no[3]; +} Object_Nearest2dPrecalc; + + +static void nearest2d_precalc( + Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar, + const float dist_px, float obmat[4][4], + const float ray_origin_local[3], const float ray_direction_local[3], + const float mval[2], const float depth_range[2]) +{ + precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat); + copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local); + copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local); + copy_v2_v2(neasrest_precalc->mval, mval); + copy_v2_v2(neasrest_precalc->depth_range, depth_range); + + for (int i = 0; i < 3; i++) { + neasrest_precalc->ray_inv_dir[i] = + (neasrest_precalc->ray_direction_local[i] != 0.0f) ? + (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX; + neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f); + neasrest_precalc->r_axis_closest[i] = true; + } +} + +static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data) +{ + Object_Nearest2dPrecalc *data = user_data; + float local_bvmin[3], local_bvmax[3]; + if (data->sign[0]) { + local_bvmin[0] = bounds[0].max; + local_bvmax[0] = bounds[0].min; + } + else { + local_bvmin[0] = bounds[0].min; + local_bvmax[0] = bounds[0].max; + } + if (data->sign[1]) { + local_bvmin[1] = bounds[1].max; + local_bvmax[1] = bounds[1].min; + } + else { + local_bvmin[1] = bounds[1].min; + local_bvmax[1] = bounds[1].max; + } + if (data->sign[2]) { + local_bvmin[2] = bounds[2].max; + local_bvmax[2] = bounds[2].min; + } + else { + local_bvmin[2] = bounds[2].min; + local_bvmax[2] = bounds[2].max; + } + + const float tmin[3] = { + (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + const float tmax[3] = { + (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + float va[3], vb[3]; + float rtmin, rtmax; + int main_axis; + + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + rtmax = tmax[0]; + va[0] = vb[0] = local_bvmax[0]; + main_axis = 3; + data->r_axis_closest[0] = data->sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + rtmax = tmax[1]; + va[1] = vb[1] = local_bvmax[1]; + main_axis = 2; + data->r_axis_closest[1] = data->sign[1]; + } + else { + rtmax = tmax[2]; + va[2] = vb[2] = local_bvmax[2]; + main_axis = 1; + data->r_axis_closest[2] = data->sign[2]; + } + + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + rtmin = tmin[0]; + va[0] = vb[0] = local_bvmin[0]; + main_axis -= 3; + data->r_axis_closest[0] = !data->sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + rtmin = tmin[1]; + va[1] = vb[1] = local_bvmin[1]; + main_axis -= 1; + data->r_axis_closest[1] = !data->sign[1]; + } + else { + rtmin = tmin[2]; + va[2] = vb[2] = local_bvmin[2]; + main_axis -= 2; + data->r_axis_closest[2] = !data->sign[2]; + } + if (main_axis < 0) { + main_axis += 3; + } + + /* if rtmin < rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { +#ifdef IGNORE_BEHIND_RAY + /* `if rtmax < depth_min`, the whole `AABB` is behind us */ + if (rtmax < min_depth) { + return fallback; + } +#endif + const float proj = rtmin * data->ray_direction_local[main_axis]; + data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); + return true; + } +#ifdef IGNORE_BEHIND_RAY + /* `if rtmin < depth_min`, the whole `AABB` is behing us */ + else if (rtmin < min_depth) { + return fallback; + } +#endif + if (data->sign[main_axis]) { + va[main_axis] = local_bvmax[main_axis]; + vb[main_axis] = local_bvmin[main_axis]; + } + else { + va[main_axis] = local_bvmin[main_axis]; + vb[main_axis] = local_bvmax[main_axis]; + } + float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]); + + float (*pmat)[4] = data->projectdefs.pmat; + float depth_a = mul_project_m4_v3_zfac(pmat, va); + float depth_b = depth_a + pmat[main_axis][3] * scale; + + float va2d[2] = { + (dot_m4_v3_row_x(pmat, va) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, va) + pmat[3][1]), + }; + float vb2d[2] = { + (va2d[0] + pmat[main_axis][0] * scale) / depth_b, + (va2d[1] + pmat[main_axis][1] * scale) / depth_b, + }; + + va2d[0] /= depth_a; + va2d[1] /= depth_a; + + va2d[0] += 1.0f; + va2d[1] += 1.0f; + vb2d[0] += 1.0f; + vb2d[1] += 1.0f; + + va2d[0] *= data->projectdefs.win_half[0]; + va2d[1] *= data->projectdefs.win_half[1]; + vb2d[0] *= data->projectdefs.win_half[0]; + vb2d[1] *= data->projectdefs.win_half[1]; + + //float dvec[2], edge[2], rdist; + //sub_v2_v2v2(dvec, data->mval, va2d); + //sub_v2_v2v2(edge, vb2d, va2d); + float rdist; + short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]}; + short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]}; + float lambda = dvec[0] * edge[0] + dvec[1] * edge[1]; + if (lambda != 0.0f) { + lambda /= edge[0] * edge[0] + edge[1] * edge[1]; + if (lambda <= 0.0f) { + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = true; + } + else if (lambda >= 1.0f) { + rdist = len_squared_v2v2(data->mval, vb2d); + data->r_axis_closest[main_axis] = false; + } + else { + va2d[0] += edge[0] * lambda; + va2d[1] += edge[1] * lambda; + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = lambda < 0.5f; + } + } + else { + rdist = len_squared_v2v2(data->mval, va2d); + } + return rdist < data->projectdefs.dist_px_sq; +} + +static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + const float co[3] = { + (bounds[0].min + bounds[0].max) / 2, + (bounds[1].min + bounds[1].max) / 2, + (bounds[2].min + bounds[2].max) / 2, + }; + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_vert_dist( + &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP, + neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no); + neasrest_precalc->index = index; + } + return true; +} + +static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + + const float *v_pair[2]; + get_edge_verts(neasrest_precalc->userdata, index, v_pair); + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_edge_dist( + &neasrest_precalc->projectdefs, v_pair[0], v_pair[1], + neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local, + VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]); + neasrest_precalc->index = index; + } + return true; +} + +static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata) +{ + const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest; + return r_axis_closest[axis]; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Internal Object Snapping API + * \{ */ + static bool snapArmature( - Object *ob, bArmature *arm, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const short snap_to, const float origin[3], const float dir[3], + const float mval[2], const enum eViewProj view_proj, const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_origin_local[3], ray_normal_local[3]; bool retval = false; - invert_m4_m4(imat, obmat); + float ray_start_local[3], ray_normal_local[3]; + if (snap_to != SCE_SNAP_MODE_VERTEX) { + float imat[4][4]; + invert_m4_m4(imat, obmat); - mul_v3_m4v3(ray_origin_local, imat, ray_origin); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + copy_v3_v3(ray_start_local, origin); + copy_v3_v3(ray_normal_local, dir); + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + } - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); if (arm->edbo) { - EditBone *eBone; - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { + for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->layer & arm->layer) { /* skip hidden or moving (selected) bones */ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= test_vert( - eBone->head, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - retval |= test_vert( - eBone->tail, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= test_edge( - eBone->head, eBone->tail, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } @@ -360,11 +778,8 @@ static bool snapArmature( } } else if (ob->pose && ob->pose->chanbase.first) { - bPoseChannel *pchan; - Bone *bone; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; /* skip hidden bones */ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { const float *head_vec = pchan->pose_head; @@ -372,26 +787,22 @@ static bool snapArmature( switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= test_vert( - head_vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - retval |= test_vert( - tail_vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, head_vec, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= test_edge( - head_vec, tail_vec, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } } } if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); mul_m4_v3(obmat, r_loc); return true; } @@ -399,39 +810,26 @@ static bool snapArmature( } static bool snapCurve( - Object *ob, Curve *cu, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_origin_local[3], ray_normal_local[3]; bool retval = false; - int u; - - Nurb *nu; /* only vertex snapping mode (eg control points and handles) supported for now) */ if (snap_to != SCE_SNAP_MODE_VERTEX) { return retval; } - invert_m4_m4(imat, obmat); - - copy_v3_v3(ray_origin_local, ray_origin); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_origin_local); - mul_mat3_m4_v3(imat, ray_normal_local); - - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); - for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { - for (u = 0; u < nu->pntsu; u++) { + for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { + for (int u = 0; u < nu->pntsu; u++) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { @@ -441,26 +839,20 @@ static bool snapCurve( if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { break; } - retval |= test_vert( - nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { - retval |= test_vert( - nu->bezt[u].vec[0], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc); } if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { - retval |= test_vert( - nu->bezt[u].vec[2], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc); } } else { @@ -468,26 +860,20 @@ static bool snapCurve( if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { break; } - retval |= test_vert( - nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } else { /* curve is not visible outside editmode if nurb length less than two */ if (nu->pntsu > 1) { if (nu->bezt) { - retval |= test_vert( - nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); } else { - retval |= test_vert( - nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } } @@ -499,6 +885,7 @@ static bool snapCurve( } } if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); mul_m4_v3(obmat, r_loc); return true; } @@ -507,11 +894,11 @@ static bool snapCurve( /* may extend later (for now just snaps to empty center) */ static bool snapEmpty( - Object *ob, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { @@ -520,17 +907,19 @@ static bool snapEmpty( if (ob->transflag & OB_DUPLI) { return retval; } + /* for now only vertex supported */ switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { - float ob_loc[3], ob_scale[3] = {1.0, 1.0, 1.0}; - copy_v3_v3(ob_loc, obmat[3]); - - retval |= test_vert( - ob_loc, NULL, ray_origin, ray_normal, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, NULL); + float tmp_co[3]; + copy_v3_v3(tmp_co, obmat[3]); + if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + retval = true; + } break; } default: @@ -541,19 +930,23 @@ static bool snapEmpty( } static bool snapCamera( - Scene *scene, Object *object, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const SnapObjectContext *sctx, Object *object, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { + Scene *scene = sctx->scene; + + PreDefProject projectdefs; + precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL); + float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; bool retval = false; MovieClip *clip = BKE_object_movieclip_get(scene, object, false); MovieTracking *tracking; - float ray_origin_local[3], ray_normal_local[3]; if (clip == NULL) { return retval; @@ -584,9 +977,6 @@ static bool snapCamera( reconstructed_camera_imat[4][4]; float (*vertex_obmat)[4]; - copy_v3_v3(ray_origin_local, ray_origin); - copy_v3_v3(ray_normal_local, ray_normal); - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, CFRA, reconstructed_camera_mat); @@ -603,26 +993,16 @@ static bool snapCamera( copy_v3_v3(bundle_pos, track->bundle_pos); if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - mul_m4_v3(orig_camera_imat, ray_origin_local); - mul_mat3_m4_v3(orig_camera_imat, ray_normal_local); vertex_obmat = orig_camera_mat; } else { mul_m4_v3(reconstructed_camera_imat, bundle_pos); - mul_m4_v3(imat, ray_origin_local); - mul_mat3_m4_v3(imat, ray_normal_local); vertex_obmat = obmat; } - float ob_scale[3]; - mat4_to_size(ob_scale, vertex_obmat); - - retval |= test_vert( - bundle_pos, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - - mul_m4_v3(vertex_obmat, r_loc); + mul_m4_v3(vertex_obmat, bundle_pos); + retval |= test_projected_vert_dist( + &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc); } } @@ -632,7 +1012,11 @@ static bool snapCamera( break; } - return retval; + if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + return true; + } + return false; } static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) @@ -643,44 +1027,45 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) struct NearestDM_Data { void *bvhdata; - bool is_persp; - const float *ray_depth_range; - + const float *depth_range; float *ray_depth; }; -static void test_vert_depth_cb( +static void test_vert_ray_dist_cb( void *userdata, const float origin[3], const float dir[3], const float scale[3], int index, BVHTreeNearest *nearest) { struct NearestDM_Data *ndata = userdata; - const BVHTreeFromMesh *data = ndata->bvhdata; - const MVert *vert = data->vert + index; + const struct BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *co = get_vert_co(data, index); - if (test_vert( - vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, NULL)) + if (test_vert_dist( + co, origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) { - normal_short_to_float_v3(nearest->no, vert->no); + copy_vert_no(data, index, nearest->no); nearest->index = index; } } -static void test_edge_depth_cb( +static void test_edge_ray_dist_cb( void *userdata, const float origin[3], const float dir[3], const float scale[3], int index, BVHTreeNearest *nearest) { struct NearestDM_Data *ndata = userdata; - const BVHTreeFromMesh *data = ndata->bvhdata; - const MVert *vert = data->vert; - const MEdge *edge = data->edge + index; - - if (test_edge( - vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) + BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *v_pair[2]; + get_edge_verts(data, index, v_pair); + + if (test_edge_dist( + v_pair[0], v_pair[1], origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) { + sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]); nearest->index = index; } } @@ -688,10 +1073,11 @@ static void test_edge_depth_cb( static bool snapDerivedMesh( SnapObjectContext *sctx, Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, - const short snap_to, const bool is_persp, bool do_bb, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) @@ -703,7 +1089,7 @@ static bool snapDerivedMesh( return retval; } } - if (snap_to == SCE_SNAP_MODE_EDGE) { + else if (snap_to == SCE_SNAP_MODE_EDGE) { if (dm->getNumEdges(dm) == 0) { return retval; } @@ -715,7 +1101,7 @@ static bool snapDerivedMesh( } { - bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp; + bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO); float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ @@ -823,28 +1209,30 @@ static bool snapDerivedMesh( } } + if (!treedata || !treedata->tree) { + return retval; + } + if (snap_to == SCE_SNAP_MODE_FACE) { /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already * been *inside* boundbox, leading to snap failures (see T38409). * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ if (need_ray_start_correction_init) { /* We *need* a reasonably valid len_diff in this case. * Use BHVTree to find the closest face from ray_start_local. */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - } + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); } } float ray_org_local[3]; @@ -856,8 +1244,7 @@ static bool snapDerivedMesh( * away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff + ray_depth_range[0]); + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0]); local_depth -= len_diff; } else { @@ -874,24 +1261,19 @@ static bool snapDerivedMesh( data.local_scale = local_scale; data.ob = ob; data.ob_uuid = ob_index; - data.dm = dm; data.hit_list = r_hit_list; data.retval = retval; BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); retval = data.retval; } else { - BVHTreeRayHit hit; + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( + if (BLI_bvhtree_ray_cast( treedata->tree, ray_start_local, ray_normal_local, 0.0f, &hit, treedata->raycast_callback, treedata) != -1) { @@ -900,12 +1282,15 @@ static bool snapDerivedMesh( if (hit.dist <= *ray_depth) { *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); /* back to worldspace */ mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } retval = true; @@ -917,51 +1302,78 @@ static bool snapDerivedMesh( } } else { - /* Vert & edge use nearly identical logic. */ - BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)); + const ARegion *ar = sctx->v3d_data.ar; float ray_org_local[3]; - copy_v3_v3(ray_org_local, ray_origin); mul_m4_v3(imat, ray_org_local); - BVHTreeNearest nearest; + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH}; - nearest.index = -1; - nearest.dist_sq = *dist_to_ray_sq; + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; - struct NearestDM_Data userdata; - userdata.bvhdata = treedata; - userdata.is_persp = is_persp; - userdata.ray_depth_range = ray_depth_range; - userdata.ray_depth = ray_depth; + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - BVHTree_NearestToRayCallback callback = - (snap_to == SCE_SNAP_MODE_VERTEX) ? - test_vert_depth_cb : test_edge_depth_cb; + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); - if (treedata->tree && - (is_persp ? - BLI_bvhtree_find_nearest_to_ray_angle( - treedata->tree, ray_org_local, ray_normal_local, - true, ob_scale, &nearest, callback, &userdata) : - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_org_local, ray_normal_local, - true, ob_scale, &nearest, callback, &userdata)) != -1) - { - copy_v3_v3(r_loc, nearest.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; } - *dist_to_ray_sq = nearest.dist_sq; + } + else { + BVHTreeNearest nearest; - retval = true; + nearest.index = -1; + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; + + retval = true; + } } } @@ -975,47 +1387,14 @@ static bool snapDerivedMesh( return retval; } -static void test_bmvert_depth_cb( - void *userdata, const float origin[3], const float dir[3], - const float scale[3], int index, BVHTreeNearest *nearest) -{ - struct NearestDM_Data *ndata = userdata; - const BMEditMesh *em = ndata->bvhdata; - BMVert *eve = BM_vert_at_index(em->bm, index); - - if (test_vert( - eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) - { - nearest->index = index; - } -} - -static void test_bmedge_depth_cb( - void *userdata, const float origin[3], const float dir[3], - const float scale[3], int index, BVHTreeNearest *nearest) -{ - struct NearestDM_Data *ndata = userdata; - const BMEditMesh *em = ndata->bvhdata; - BMEdge *eed = BM_edge_at_index(em->bm, index); - - if (test_edge( - eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) - { - nearest->index = index; - } -} - static bool snapEditMesh( SnapObjectContext *sctx, Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) @@ -1143,6 +1522,10 @@ static bool snapEditMesh( } } + if (!treedata || !treedata->tree) { + return retval; + } + if (snap_to == SCE_SNAP_MODE_FACE) { float ray_start_local[3]; copy_v3_v3(ray_start_local, ray_start); @@ -1160,35 +1543,32 @@ static bool snapEditMesh( * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ float len_diff = 0.0f; - if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Use BHVTree to find the closest face from ray_start_local. */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) - { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, - * to avoid precision issues with very far away ray_start values - * (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff + ray_depth_range[0]); - local_depth -= len_diff; - } + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + if (BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) + { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, + * to avoid precision issues with very far away ray_start values + * (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0]); + local_depth -= len_diff; } } if (r_hit_list) { @@ -1202,7 +1582,6 @@ static bool snapEditMesh( data.local_scale = local_scale; data.ob = ob; data.ob_uuid = ob_index; - data.dm = NULL; data.hit_list = r_hit_list; data.retval = retval; @@ -1213,13 +1592,9 @@ static bool snapEditMesh( retval = data.retval; } else { - BVHTreeRayHit hit; + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( + if (BLI_bvhtree_ray_cast( treedata->tree, ray_start_local, ray_normal_local, 0.0f, &hit, treedata->raycast_callback, treedata) != -1) { @@ -1228,12 +1603,15 @@ static bool snapEditMesh( if (hit.dist <= *ray_depth) { *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); /* back to worldspace */ mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } retval = true; @@ -1245,51 +1623,78 @@ static bool snapEditMesh( } } else { - /* Vert & edge use nearly identical logic. */ - BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)); + const ARegion *ar = sctx->v3d_data.ar; float ray_org_local[3]; - copy_v3_v3(ray_org_local, ray_origin); mul_m4_v3(imat, ray_org_local); - BVHTreeNearest nearest; + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH}; - nearest.index = -1; - nearest.dist_sq = *dist_to_ray_sq; + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; - struct NearestDM_Data userdata; - userdata.bvhdata = em; - userdata.is_persp = is_persp; - userdata.ray_depth_range = ray_depth_range; - userdata.ray_depth = ray_depth; + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - BVHTree_NearestToRayCallback callback = - (snap_to == SCE_SNAP_MODE_VERTEX) ? - test_bmvert_depth_cb : test_bmedge_depth_cb; + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); - if (treedata->tree && - (is_persp ? - BLI_bvhtree_find_nearest_to_ray_angle( - treedata->tree, ray_org_local, ray_normal_local, - false, ob_scale, &nearest, callback, &userdata) : - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_org_local, ray_normal_local, - false, ob_scale, &nearest, callback, &userdata)) != -1) - { - copy_v3_v3(r_loc, nearest.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; } - *dist_to_ray_sq = nearest.dist_sq; + } + else { + BVHTreeNearest nearest; - retval = true; + nearest.index = -1; + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; + + retval = true; + } } } @@ -1305,26 +1710,28 @@ static bool snapEditMesh( /** * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; - * \param ray_depth_range: - * - 0: distance from the ray_origin to the clipping plane min (can be negative). - * - 1: maximum distance, elements outside this are ignored. - * \param ray_depth: maximum depth allowed for r_co. * * \note Duplicate args here are documented at #snapObjectsRay */ static bool snapObject( SnapObjectContext *sctx, Object *ob, float obmat[4][4], const unsigned int ob_index, - bool use_obedit, const short snap_to, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + bool use_obedit, const short snap_to, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp; + const enum eViewProj view_proj = + ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE : + (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO); + + const ARegion *ar = sctx->v3d_data.ar; + bool retval = false; if (ob->type == OB_MESH) { @@ -1334,9 +1741,9 @@ static bool snapObject( em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, ob, em, obmat, ob_index, - snap_to, is_persp, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + snap_to, mval, view_proj, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); } @@ -1353,42 +1760,43 @@ static bool snapObject( } retval = snapDerivedMesh( sctx, ob, dm, obmat, ob_index, - snap_to, is_persp, true, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + snap_to, mval, view_proj, true, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); dm->release(dm); } } - else if (ob->type == OB_ARMATURE) { - retval = snapArmature( - ob, ob->data, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_CURVE) { - retval = snapCurve( - ob, ob->data, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_EMPTY) { - retval = snapEmpty( - ob, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_CAMERA) { - retval = snapCamera( - sctx->scene, ob, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); + else if (snap_to != SCE_SNAP_MODE_FACE) { + if (ob->type == OB_ARMATURE) { + retval = snapArmature( + ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal, + mval, view_proj, depth_range, dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CURVE) { + retval = snapCurve( + ar, ob, ob->data, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty( + ar, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CAMERA) { + retval = snapCamera( + sctx, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } } if (retval) { @@ -1414,16 +1822,18 @@ static bool snapObject( * \param snap_select: from enum SnapSelect. * * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping. + * \param mval: Mouse coords. + * When NULL, ray-casting is handled without any projection matrix correction. * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. * \param ray_start: ray_origin moved for the start clipping plane (clip_min). * \param ray_normal: Unit length direction of the ray. + * \param depth_range: distances of clipe plane min and clip plane max; * * Read/Write Args * --------------- * * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored. - * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared. - * resulting of the function #dist_px_to_dist3d_or_tangent. + * \param dist_px: Maximum threshold distance (in pixels). * * Output Args * ----------- @@ -1440,10 +1850,11 @@ static bool snapObject( static bool snapObjectsRay( SnapObjectContext *sctx, const unsigned short snap_to, const SnapSelect snap_select, - const bool use_object_edit_cage, + const bool use_object_edit_cage, const float mval[2], const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], @@ -1451,14 +1862,6 @@ static bool snapObjectsRay( { bool retval = false; - float dvec[3]; - sub_v3_v3v3(dvec, ray_start, ray_origin); - - const float ray_depth_range[2] = { - dot_v3v3(dvec, ray_normal), - *ray_depth, - }; - unsigned int ob_index = 0; Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; Base *base_act = sctx->scene->basact; @@ -1493,9 +1896,9 @@ static bool snapObjectsRay( retval |= snapObject( sctx, dupli_snap, dupli_ob->mat, ob_index++, - use_obedit_dupli, snap_to, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + use_obedit_dupli, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1507,9 +1910,9 @@ static bool snapObjectsRay( retval |= snapObject( sctx, ob_snap, ob->obmat, ob_index++, - use_obedit, snap_to, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + use_obedit, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -1616,13 +2019,12 @@ bool ED_transform_snap_object_project_ray_ex( float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - float dist_to_ray_sq = 0.0f; - + const float depth_range[2] = {0.0f, FLT_MAX}; return snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - ray_start, ray_start, ray_normal, - ray_depth, &dist_to_ray_sq, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + ray_depth, NULL, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -1641,8 +2043,7 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { - float dist_to_ray_sq = 0.0f; - + const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -1653,9 +2054,9 @@ bool ED_transform_snap_object_project_ray_all( bool retval = snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - ray_start, ray_start, ray_normal, - &ray_depth, &dist_to_ray_sq, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + &ray_depth, NULL, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -1710,11 +2111,6 @@ bool ED_transform_snap_object_project_ray( ray_depth = &ray_depth_fallback; } - float no_fallback[3]; - if (r_no == NULL) { - r_no = no_fallback; - } - return transform_snap_context_project_ray_impl( sctx, params, @@ -1733,11 +2129,6 @@ static bool transform_snap_context_project_view3d_mixed_impl( float ray_depth = BVH_RAYCAST_DIST_MAX; bool is_hit = false; - float r_no_dummy[3]; - if (r_no == NULL) { - r_no = r_no_dummy; - } - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; BLI_assert(snap_to_flag != 0); @@ -1764,21 +2155,6 @@ static bool transform_snap_context_project_view3d_mixed_impl( } /** - * From a threshold (maximum distance to snap in pixels) returns: - * - * - The *real* distance (3D) if you are in orthographic-view. - * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. - */ -static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) -{ - const RegionView3D *rv3d = ar->regiondata; - if (ar->winx >= ar->winy) - return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; - else - return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; -} - -/** * Convenience function for performing snapping. * * Given a 2D region value, snap to vert/edge/face. @@ -1814,55 +2190,37 @@ bool ED_transform_snap_object_project_view3d_ex( float *ray_depth, float r_loc[3], float r_no[3], int *r_index) { - float ray_start[3], ray_normal[3], ray_origin[3]; + float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3]; - float ray_depth_fallback; - if (ray_depth == NULL) { - ray_depth_fallback = BVH_RAYCAST_DIST_MAX; - ray_depth = &ray_depth_fallback; - } + const ARegion *ar = sctx->v3d_data.ar; + const RegionView3D *rv3d = ar->regiondata; - if (!ED_view3d_win_to_ray_ex( - sctx->v3d_data.ar, sctx->v3d_data.v3d, - mval, ray_origin, ray_normal, ray_start, true)) - { + ED_view3d_win_to_origin(ar, mval, ray_origin); + ED_view3d_win_to_vector(ar, mval, ray_normal); + + ED_view3d_clip_range_get( + sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, + &depth_range[0], &depth_range[1], false); + + madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); + madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); + + if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { return false; } - float radius, dist_to_ray_sq = 0.0f; - if (dist_px) { - radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px); - /** - * Workaround to use of cone (Instead of project the radius on view plane): - * In perspective view, the radius of the cone may decrease depending on the ray direction. - * This is more evident with small values of the `Viewport lens angle`. - * The threshold becomes distorted that way. - */ - RegionView3D *rv3d = sctx->v3d_data.ar->regiondata; - if (rv3d->is_persp) { - float view_dir[3]; - negate_v3_v3(view_dir, rv3d->viewinv[2]); - normalize_v3(view_dir); - radius *= dot_v3v3(ray_normal, view_dir); - } - - dist_to_ray_sq = SQUARE(radius); + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; } - if (snapObjectsRay( + return snapObjectsRay( sctx, snap_to, params->snap_select, params->use_object_edit_cage, - ray_origin, ray_start, ray_normal, - ray_depth, &dist_to_ray_sq, - r_loc, r_no, r_index, NULL, NULL, NULL)) - { - if (dist_px) { - *dist_px *= sqrtf(dist_to_ray_sq) / radius; - } - return true; - } - - return false; + mval, ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, + r_loc, r_no, r_index, NULL, NULL, NULL); } bool ED_transform_snap_object_project_view3d( |