diff options
Diffstat (limited to 'source/blender/editors')
48 files changed, 1862 insertions, 1209 deletions
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index f92967ef5ff..afc4e5c9e61 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -886,7 +886,7 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot) /* identifiers */ ot->name = "Add Driver"; ot->idname = "ANIM_OT_driver_button_add"; - ot->description = "Add driver(s) for the property(s) connected represented by the highlighted button"; + ot->description = "Add driver(s) for the property(s) represented by the highlighted button"; /* callbacks */ /* NOTE: No exec, as we need all these to use the current context info diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 87d75aa8fad..b62714700fa 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -1086,9 +1086,23 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S mval[1] = dd->mval[1]; /* try to snap to closer object */ - found = snapObjectsContext( - C, mval, SNAP_NOT_SELECTED, - vec, no, &dist_px); + { + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), 0, + CTX_wm_region(C), CTX_wm_view3d(C)); + + found = ED_transform_snap_object_project_view3d_mixed( + snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_SELECTED, + .snap_to_flag = SCE_SELECT_FACE, + }, + mval, &dist_px, true, + vec, no); + + ED_transform_snap_object_context_destroy(snap_context); + } + if (found == 1) { pt->type = dd->type; pt->mode = PT_SNAP; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 9df611b3216..395da2cd2f1 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4993,11 +4993,22 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (use_proj) { const float mval[2] = {UNPACK2(event->mval)}; - float no_dummy[3]; - float dist_px_dummy; - snapObjectsContext( - C, mval, SNAP_NOT_OBEDIT, - location, no_dummy, &dist_px_dummy); + + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), vc.scene, 0, + vc.ar, vc.v3d); + + ED_transform_snap_object_project_view3d_mixed( + snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_OBEDIT, + .snap_to_flag = SCE_SELECT_FACE, + }, + mval, NULL, true, + location, NULL); + + + ED_transform_snap_object_context_destroy(snap_context); } if ((cu->flag & CU_3D) == 0) { diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 5c74a3e43c2..d24c33984ee 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -84,7 +84,7 @@ static float depth_read_zbuf(const ViewContext *vc, int x, int y) static bool depth_unproject( const ARegion *ar, const bglMats *mats, - const int mval[2], const float depth, + const int mval[2], const double depth, float r_location_world[3]) { double p[3]; @@ -115,7 +115,7 @@ static bool depth_read_normal( for (int y = 0; y < 2; y++) { const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - float depth = depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]); + const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { depths_valid[i] = true; @@ -170,6 +170,11 @@ struct StrokeElem { float mval[2]; float location_world[3]; float location_local[3]; + + /* surface normal, may be zero'd */ + float normal_world[3]; + float normal_local[3]; + float pressure; }; @@ -225,10 +230,26 @@ struct CurveDrawData { void *draw_handle_view; }; -static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem) +static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd, const float pressure) { const Curve *cu = cdd->vc.obedit->data; - return ((selem->pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2; + return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2; +} + +static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem) +{ + return stroke_elem_radius_from_pressure(cdd, selem->pressure); +} + +static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure) +{ + if ((cdd->radius.offset != 0.0f) && !is_zero_v3(selem->normal_local)) { + const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) - + stroke_elem_radius_from_pressure(cdd, selem->pressure); + madd_v3_v3fl(selem->location_local, selem->normal_local, adjust); + mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local); + } + selem->pressure = pressure; } static void stroke_elem_interp( @@ -249,7 +270,7 @@ static bool stroke_elem_project( const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], const float radius_offset, const float radius, - float r_location_world[3]) + float r_location_world[3], float r_normal_world[3]) { View3D *v3d = cdd->vc.v3d; ARegion *ar = cdd->vc.ar; @@ -266,6 +287,9 @@ static bool stroke_elem_project( float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) { madd_v3_v3v3fl(r_location_world, ray_origin, ray_direction, lambda); + if (r_normal_world) { + zero_v3(r_normal_world); + } is_location_world_set = true; } } @@ -275,15 +299,21 @@ static bool stroke_elem_project( ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) { - float depth = depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]); + const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { is_location_world_set = true; + if (r_normal_world) { + zero_v3(r_normal_world); + } if (radius_offset != 0.0f) { float normal[3]; if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { madd_v3_v3fl(r_location_world, normal, radius_offset * radius); + if (r_normal_world) { + copy_v3_v3(r_normal_world, normal); + } } } } @@ -305,17 +335,28 @@ static bool stroke_elem_project_fallback( const int mval_i[2], const float mval_fl[2], const float radius_offset, const float radius, const float location_fallback_depth[3], - float r_location_world[3], float r_location_local[3]) + float r_location_world[3], float r_location_local[3], + float r_normal_world[3], float r_normal_local[3]) { bool is_depth_found = stroke_elem_project( cdd, mval_i, mval_fl, radius_offset, radius, - r_location_world); + r_location_world, r_normal_world); if (is_depth_found == false) { ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world); + zero_v3(r_normal_local); } mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world); + if (!is_zero_v3(r_normal_world)) { + copy_v3_v3(r_normal_local, r_normal_world); + mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local); + normalize_v3(r_normal_local); + } + else { + zero_v3(r_normal_local); + } + return is_depth_found; } @@ -333,7 +374,8 @@ static bool stroke_elem_project_fallback_elem( cdd, mval_i, selem->mval, cdd->radius.offset, radius, location_fallback_depth, - selem->location_world, selem->location_local); + selem->location_world, selem->location_local, + selem->normal_world, selem->normal_local); } /** \} */ @@ -602,7 +644,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event) if (stroke_elem_project( cdd, event->mval, mval_fl, 0.0f, 0.0f, - location_no_offset)) + location_no_offset, NULL)) { sub_v3_v3v3(cdd->project.offset, cdd->prev.location_world_valid, location_no_offset); if (!is_zero_v3(cdd->project.offset)) { @@ -628,7 +670,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) view3d_set_viewcontext(C, &cdd->vc); if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) { MEM_freeN(cdd); - BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport."); + BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport"); return false; } } @@ -684,7 +726,7 @@ static void curve_draw_exec_precalc(wmOperator *op) prop = RNA_struct_find_property(op->ptr, "corner_angle"); if (!RNA_property_is_set(op->ptr, prop)) { - const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : M_PI; + const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : (float)M_PI; RNA_property_float_set(op->ptr, prop, corner_angle); } @@ -738,20 +780,20 @@ static void curve_draw_exec_precalc(wmOperator *op) selem_prev = selem; } - if (cps->radius_taper_start != 0.0) { - selem_array[0]->pressure = 0.0f; + if (cps->radius_taper_start != 0.0f) { const float len_taper_max = cps->radius_taper_start * len_3d; - for (i = 1; i < stroke_len && lengths[i] < len_taper_max; i++) { - selem_array[i]->pressure *= lengths[i] / len_taper_max; + for (i = 0; i < stroke_len && lengths[i] < len_taper_max; i++) { + const float pressure_new = selem_array[i]->pressure * (lengths[i] / len_taper_max); + stroke_elem_pressure_set(cdd, selem_array[i], pressure_new); } } - if (cps->radius_taper_end != 0.0) { - selem_array[stroke_len - 1]->pressure = 0.0f; + if (cps->radius_taper_end != 0.0f) { const float len_taper_max = cps->radius_taper_end * len_3d; const float len_taper_min = len_3d - len_taper_max; - for (i = stroke_len - 2; i > 0 && lengths[i] > len_taper_min; i--) { - selem_array[i]->pressure *= (len_3d - lengths[i]) / len_taper_max; + for (i = stroke_len - 1; i > 0 && lengths[i] > len_taper_min; i--) { + const float pressure_new = selem_array[i]->pressure * ((len_3d - lengths[i]) / len_taper_max); + stroke_elem_pressure_set(cdd, selem_array[i], pressure_new); } } @@ -787,9 +829,9 @@ static int curve_draw_exec(bContext *C, wmOperator *op) ED_curve_deselect_all(cu->editnurb); - const double radius_min = cps->radius_min; - const double radius_max = cps->radius_max; - const double radius_range = cps->radius_max - cps->radius_min; + const float radius_min = cps->radius_min; + const float radius_max = cps->radius_max; + const float radius_range = cps->radius_max - cps->radius_min; Nurb *nu = MEM_callocN(sizeof(Nurb), __func__); nu->pntsv = 1; @@ -840,7 +882,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op) unsigned int *corners = NULL; unsigned int corners_len = 0; - if (corner_angle < M_PI) { + if (corner_angle < (float)M_PI) { /* this could be configurable... */ const float corner_radius_min = error_threshold / 8; const float corner_radius_max = error_threshold * 2; @@ -1058,7 +1100,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) cdd->project.use_depth = true; } else { - BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane."); + BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane"); cdd->project.use_depth = false; } } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 34e640a4b7b..c39a3aa5cfc 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -41,7 +41,7 @@ #include "BLI_listbase.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_gpencil.h" diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index db8085a6696..39df52e5f68 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -43,6 +43,8 @@ struct wmEvent; struct wmKeyConfig; struct wmKeyMap; struct wmOperatorType; +struct Main; +struct SnapObjectContext; void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid); void transform_operatortypes(void); @@ -187,27 +189,9 @@ bool peelObjectsContext( struct ListBase *r_depth_peels); bool snapObjectsTransform( struct TransInfo *t, const float mval[2], SnapSelect snap_select, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px); -bool snapObjectsContext( - struct bContext *C, const float mval[2], SnapSelect snap_select, - /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px); -/* taks args for all settings */ -bool snapObjectsEx( - struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_mode, - float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px); -bool snapObjectsRayEx( - struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_mode, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, - struct Object **r_ob, float r_obmat[4][4]); - + float r_loc[3], float r_no[3]); bool snapNodesTransform( struct TransInfo *t, const int mval[2], SnapSelect snap_select, /* return args */ @@ -217,4 +201,67 @@ bool snapNodesContext( /* return args */ float r_loc[2], float *r_dist_px, char *r_node_border); + +/* transform_snap_object.c */ + +/* ED_transform_snap_object_*** API */ +struct SnapObjectParams { + SnapSelect snap_select; + union { + unsigned int snap_to : 4; + /* snap_target_flag: Snap to vert/edge/face. */ + unsigned int snap_to_flag : 4; + }; + /* use editmode cage */ + unsigned int use_object_edit : 1; + /* special context sensitive handling for the active object */ + unsigned int use_object_active : 1; +}; + +enum { + SNAP_OBJECT_USE_CACHE = (1 << 0), +}; + +typedef struct SnapObjectContext SnapObjectContext; +SnapObjectContext *ED_transform_snap_object_context_create( + struct Main *bmain, struct Scene *scene, int flag); +SnapObjectContext *ED_transform_snap_object_context_create_view3d( + struct Main *bmain, struct Scene *scene, int flag, + /* extra args for view3d */ + struct ARegion *ar, struct View3D *v3d); +void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); + +bool ED_transform_snap_object_project_ray_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + struct Object **r_ob, float r_obmat[4][4]); +bool ED_transform_snap_object_project_ray( + SnapObjectContext *sctx, + const float ray_origin[3], const float ray_direction[3], float *ray_dist, + float r_co[3], float r_no[3]); + +bool ED_transform_snap_object_project_view3d_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + float r_loc[3], float r_no[3], int *r_index); +bool ED_transform_snap_object_project_view3d( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3]); +bool ED_transform_snap_object_project_view3d_mixed( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval_fl[2], float *dist_px, + bool use_depth, + float r_co[3], float r_no[3]); + + #endif /* __ED_TRANSFORM_H__ */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index d8a3f5e75f5..c23c2eed890 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -396,18 +396,6 @@ void ED_view3d_operator_properties_viewmat_set(struct bContext *C, struct wmOper void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, int *winy, float persmat[4][4]); #endif -bool ED_view3d_snap_from_region( - struct Scene *scene, struct View3D *v3d, struct ARegion *ar, - const float mval[2], float dist_px, - bool use_depth, bool use_obedit, - bool use_vert, bool use_edge, bool use_face, - float r_co[3], float r_no[3]); - -bool ED_view3d_snap_from_ray( - struct Scene *scene, - const float ray_start[3], const float ray_normal[3], - float r_co[3]); - /* render */ void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar); void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6c961179c6f..dd686f18a78 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -60,7 +60,7 @@ #include "PIL_time.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 2fdd84b626b..62b373c58c8 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1679,7 +1679,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) BLF_size(fontid, fstyle_points, U.dpi); BLF_enable(fontid, BLF_SHADOW); - BLF_shadow(fontid, 3, 1.0f, 1.0f, 1.0f, 0.25f); + BLF_shadow(fontid, 3, (const float[4]){1.0f, 1.0f, 1.0f, 0.25f}); BLF_shadow_offset(fontid, -1, -1); BLI_assert(UI_panel_category_is_visible(ar)); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index b3972bebd96..9e49d7e7e90 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -3006,7 +3006,8 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev } if (mt->poll && mt->poll(C, mt) == 0) - return OPERATOR_CANCELLED; + /* cancel but allow event to pass through, just like operators do */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event); layout = UI_pie_menu_layout(pie); @@ -3237,7 +3238,8 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) } if (mt->poll && mt->poll(C, mt) == 0) - return OPERATOR_CANCELLED; + /* cancel but allow event to pass through, just like operators do */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE); layout = UI_popup_menu_layout(pup); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index bfde02dbefd..423c48e5f55 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -160,7 +160,8 @@ void UI_fontstyle_draw_ex( /* set the flag */ if (fs->shadow) { font_flag |= BLF_SHADOW; - BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha); + const float shadow_color[4] = {fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha}; + BLF_shadow(fs->uifont_id, fs->shadow, shadow_color); BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); } if (fs->kerning == 1) { @@ -251,7 +252,8 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch if (fs->shadow) { BLF_enable(fs->uifont_id, BLF_SHADOW); - BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha); + const float shadow_color[4] = {fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha}; + BLF_shadow(fs->uifont_id, fs->shadow, shadow_color); BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index b1d2e329da1..3c862666aa6 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -96,7 +96,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo static char setting = 0; const char *cp = error; - /* ensure we're not getting a color after running BKE_userdef_free */ + /* ensure we're not getting a color after running BKE_blender_userdef_free */ BLI_assert(BLI_findindex(&U.themes, theme_active) != -1); BLI_assert(colorid != TH_UNDEFINED); diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 822bb429f9e..e3e8f35e7d8 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -194,12 +194,12 @@ bool ED_mask_find_nearest_diff_point(const bContext *C, /******************** add vertex *********************/ -static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point, - const float point_co[2], const float u, - MaskSplinePoint *reference_point, const bool reference_adjacent) +static void setup_vertex_point( + Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point, + const float point_co[2], const float u, const float ctime, + const MaskSplinePoint *reference_point, const bool reference_adjacent) { - MaskSplinePoint *prev_point = NULL; - MaskSplinePoint *next_point = NULL; + const MaskSplinePoint *reference_parent_point = NULL; BezTriple *bezt; float co[3]; @@ -247,14 +247,44 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint * else { bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1); } + + reference_parent_point = reference_point; } else if (reference_adjacent) { if (spline->tot_point != 1) { - int index = (int)(new_point - spline->points); - prev_point = &spline->points[(index - 1) % spline->tot_point]; - next_point = &spline->points[(index + 1) % spline->tot_point]; + MaskSplinePoint *prev_point, *next_point, *close_point; - bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1); + const int index = (int)(new_point - spline->points); + if (spline->flag & MASK_SPLINE_CYCLIC) { + prev_point = &spline->points[mod_i(index - 1, spline->tot_point)]; + next_point = &spline->points[mod_i(index + 1, spline->tot_point)]; + } + else { + prev_point = (index != 0) ? &spline->points[index - 1] : NULL; + next_point = (index != spline->tot_point - 1) ? &spline->points[index + 1] : NULL; + } + + if (prev_point && next_point) { + close_point = (len_squared_v2v2(new_point->bezt.vec[1], prev_point->bezt.vec[1]) < + len_squared_v2v2(new_point->bezt.vec[1], next_point->bezt.vec[1])) ? + prev_point : next_point; + } + else { + close_point = prev_point ? prev_point : next_point; + } + + /* handle type */ + char handle_type = 0; + if (prev_point) { + handle_type = prev_point->bezt.h2; + } + if (next_point) { + handle_type = MAX2(next_point->bezt.h2, handle_type); + } + bezt->h1 = bezt->h2 = handle_type; + + /* parent */ + reference_parent_point = close_point; /* note, we may want to copy other attributes later, radius? pressure? color? */ } @@ -264,7 +294,20 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint * copy_v3_v3(bezt->vec[1], co); copy_v3_v3(bezt->vec[2], co); - BKE_mask_parent_init(&new_point->parent); + if (reference_parent_point) { + new_point->parent = reference_parent_point->parent; + + if (new_point->parent.id) { + float parent_matrix[3][3]; + BKE_mask_point_parent_matrix_get(new_point, ctime, parent_matrix); + invert_m3(parent_matrix); + mul_m3_v2(parent_matrix, new_point->bezt.vec[1]); + } + } + else { + BKE_mask_parent_init(&new_point->parent); + } + if (spline->tot_point != 1) { BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); } @@ -348,6 +391,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2 if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, tangent, true, true, &masklay, &spline, &point, &u, NULL)) { + Scene *scene = CTX_data_scene(C); + const float ctime = CFRA; + MaskSplinePoint *new_point; int point_index = point - spline->points; @@ -357,7 +403,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2 new_point = &spline->points[point_index + 1]; - setup_vertex_point(mask, spline, new_point, co, u, NULL, true); + setup_vertex_point(mask, spline, new_point, co, u, ctime, NULL, true); /* TODO - we could pass the spline! */ BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true); @@ -375,6 +421,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2 static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2]) { + Scene *scene = CTX_data_scene(C); + const float ctime = CFRA; + MaskSpline *spline; MaskSplinePoint *point; MaskSplinePoint *new_point = NULL, *ref_point = NULL; @@ -454,7 +503,7 @@ static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay masklay->act_point = new_point; - setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, false); + setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false); if (masklay->splines_shapes.first) { point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point); @@ -468,34 +517,28 @@ static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2]) { + Scene *scene = CTX_data_scene(C); + const float ctime = CFRA; + MaskSpline *spline; - MaskSplinePoint *point; MaskSplinePoint *new_point = NULL, *ref_point = NULL; if (!masklay) { /* if there's no masklay currently operationg on, create new one */ masklay = BKE_mask_layer_new(mask, ""); mask->masklay_act = mask->masklay_tot - 1; - spline = NULL; - point = NULL; - } - else { - finSelectedSplinePoint(masklay, &spline, &point, true); } ED_mask_select_toggle_all(mask, SEL_DESELECT); - if (!spline) { - /* no selected splines in active masklay, create new spline */ - spline = BKE_mask_spline_add(masklay); - } + spline = BKE_mask_spline_add(masklay); masklay->act_spline = spline; new_point = spline->points; masklay->act_point = new_point; - setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, false); + setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false); { int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 847a7b5336e..5eaac72590b 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -137,8 +137,11 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) opdata->mesh_backup = EDBM_redo_state_store(em); opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; - opdata->twtype = v3d->twtype; - v3d->twtype = 0; + + if (v3d) { + opdata->twtype = v3d->twtype; + v3d->twtype = 0; + } } return true; @@ -206,7 +209,9 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); - v3d->twtype = opdata->twtype; + if (v3d) { + v3d->twtype = opdata->twtype; + } G.moving = 0; } MEM_freeN(opdata); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 161159d0be0..2401b749ab2 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -673,7 +673,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) /* api callbacks */ ot->invoke = edbm_dupli_extrude_cursor_invoke; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh_region_view3d; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -732,8 +732,17 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ED_view3d_context_rv3d(C); - RNA_float_set_array(op->ptr, "center", ED_view3d_cursor3d_get(scene, v3d)); - RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]); + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "center"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d)); + } + if (rv3d) { + prop = RNA_struct_find_property(op->ptr, "axis"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]); + } + } return edbm_spin_exec(C, op); } @@ -859,8 +868,17 @@ static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ED_view3d_context_rv3d(C); - RNA_float_set_array(op->ptr, "center", ED_view3d_cursor3d_get(scene, v3d)); - RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]); + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "center"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d)); + } + if (rv3d) { + prop = RNA_struct_find_property(op->ptr, "axis"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]); + } + } return edbm_screw_exec(C, op); } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 937547c99ef..097117cce6b 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -143,8 +143,10 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) opdata->mesh_backup = EDBM_redo_state_store(em); opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; - opdata->twtype = v3d->twtype; - v3d->twtype = 0; + if (v3d) { + opdata->twtype = v3d->twtype; + v3d->twtype = 0; + } } return true; @@ -162,7 +164,9 @@ static void edbm_inset_exit(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); - v3d->twtype = opdata->twtype; + if (v3d) { + v3d->twtype = opdata->twtype; + } G.moving = 0; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 17250fbfb09..84ae35fae6e 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2430,13 +2430,10 @@ static void select_linked_delimit_validate(BMesh *bm, int *delimit) } } -static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit) +static void select_linked_delimit_begin(BMesh *bm, int delimit) { struct DelimitData delimit_data = {0}; - BMIter iter; - BMEdge *e; - if (delimit & BMO_DELIM_UV) { delimit_data.cd_loop_type = CD_MLOOPUV; delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type); @@ -2447,19 +2444,13 @@ static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit /* grr, shouldn't need to alloc BMO flags here */ BM_mesh_elem_toolflags_ensure(bm); - if (selectmode == SCE_SELECT_FACE) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - const bool is_walk_ok = ( - (select_linked_delimit_test(e, delimit, &delimit_data) == false)); - BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); - } - } - else { - /* don't delimit selected edges in vert/edge mode */ + { + BMIter iter; + BMEdge *e; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { const bool is_walk_ok = ( - BM_elem_flag_test(e, BM_ELEM_SELECT) || (select_linked_delimit_test(e, delimit, &delimit_data) == false)); BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); @@ -2491,7 +2482,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) select_linked_delimit_validate(bm, &delimit); if (delimit) { - select_linked_delimit_begin(em->bm, em->selectmode, delimit); + select_linked_delimit_begin(em->bm, delimit); } if (em->selectmode & SCE_SELECT_VERTEX) { @@ -2501,6 +2492,17 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); } + /* exclude all delimited verts */ + if (delimit) { + BMEdge *e; + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) { + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + } + } + } + BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, BMW_FLAG_TEST_HIDDEN, @@ -2546,8 +2548,17 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) else if (em->selectmode & SCE_SELECT_EDGE) { BMEdge *e; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + if (delimit) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set( + e, BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG))); + } + } + else { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } } BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, @@ -2661,7 +2672,7 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in select_linked_delimit_validate(bm, &delimit); if (delimit) { - select_linked_delimit_begin(bm, em->selectmode, delimit); + select_linked_delimit_begin(bm, delimit); } /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index ee33f5f1655..44f0c6f2248 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -301,20 +301,30 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + ar, CTX_wm_view3d(C)); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float mval[2], co_proj[3], no_dummy[3]; - float dist_px_dummy; + float mval[2], co_proj[3]; if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (snapObjectsContext( - C, mval, SNAP_NOT_OBEDIT, - co_proj, no_dummy, &dist_px_dummy)) + if (ED_transform_snap_object_project_view3d_mixed( + snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_OBEDIT, + .snap_to_flag = SCE_SELECT_FACE, + }, + mval, NULL, true, + co_proj, NULL)) { mul_v3_m4v3(eve->co, obedit->imat, co_proj); } } } } + + ED_transform_snap_object_context_destroy(snap_context); } @@ -532,7 +542,7 @@ void MESH_OT_edge_collapse(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int edbm_add_edge_face__smooth_get(BMesh *bm) +static bool edbm_add_edge_face__smooth_get(BMesh *bm) { BMEdge *e; BMIter iter; @@ -700,7 +710,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) BMOperator bmop; Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); + const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; /* when this is used to dissolve we could avoid this, but checking isnt too slow */ @@ -3566,7 +3576,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) BMOperator bmop; Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); + const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 888bf832042..11d96da5786 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -700,7 +700,7 @@ static void bake_startjob(void *bkv, short *stop, short *do_update, float *progr bkr->progress = progress; RE_test_break_cb(bkr->re, NULL, thread_break); - G.is_break = false; /* blender_test_break uses this global */ + G.is_break = false; /* BKE_blender_test_break uses this global */ RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob); @@ -827,7 +827,7 @@ static int bake_image_exec(bContext *C, wmOperator *op) bkr.reports = op->reports; RE_test_break_cb(bkr.re, NULL, thread_break); - G.is_break = false; /* blender_test_break uses this global */ + G.is_break = false; /* BKE_blender_test_break uses this global */ RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL); @@ -843,7 +843,7 @@ static int bake_image_exec(bContext *C, wmOperator *op) /* used to redraw in 2.4x but this is just for exec in 2.5 */ if (!G.background) - blender_test_break(); + BKE_blender_test_break(); } BLI_end_threads(&threads); diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 7cc17e4bfea..a5d2d2c8be7 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -39,7 +39,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_blender.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_object_deform.h" @@ -426,7 +425,7 @@ static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update job->start = PIL_check_seconds_timer(); job->success = 1; - G.is_break = false; /* reset blender_test_break*/ + G.is_break = false; /* reset BKE_blender_test_break*/ /* XXX annoying hack: needed to prevent data corruption when changing * scene frame in separate threads diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index eb8ea01f750..1203889cf0e 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -49,7 +49,8 @@ #include "DNA_view3d_types.h" #include "DNA_userdef_types.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" +#include "BKE_blender_version.h" #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_colortools.h" diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index b7ad911b6f5..a1c330d9dff 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -795,8 +795,13 @@ void bglPolygonOffset(float viewdist, float dist) #endif } else { - /* should be clipping value or so... */ - offs = 0.0005f * dist; + /* This adjustment effectively results in reducing the Z value by 0.25%. + * + * winmat[14] actually evaluates to `-2 * far * near / (far - near)`, + * is very close to -0.2 with default clip range, and is used as the coefficient multiplied by `w / z`, + * thus controlling the z dependent part of the depth value. + */ + offs = winmat[14] * -0.0025f * dist; } winmat[14] -= offs; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index b8693639673..f614025fa0e 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1100,6 +1100,10 @@ static void uv_image_outset( float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, const int ibuf_x, const int ibuf_y, const bool cw) { + /* disallow shell-thickness to outset extreme values, + * otherwise near zero area UV's may extend thousands of pixels. */ + const float scale_clamp = 5.0f; + float a1, a2, a3; float puv[3][2]; /* pixelspace uv's */ float no1[2], no2[2], no3[2]; /* normals */ @@ -1150,6 +1154,10 @@ static void uv_image_outset( a2 = shell_v2v2_normal_dir_to_dist(no2, dir1); a3 = shell_v2v2_normal_dir_to_dist(no3, dir2); + CLAMP_MAX(a1, scale_clamp); + CLAMP_MAX(a2, scale_clamp); + CLAMP_MAX(a3, scale_clamp); + mul_v2_fl(no1, a1 * scaler); mul_v2_fl(no2, a2 * scaler); mul_v2_fl(no3, a3 * scaler); diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index 42f0aaab173..27d3f6648a2 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -34,7 +34,7 @@ #include "DNA_userdef_types.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_global.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 6402e2d4de7..92be88bd5c6 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2820,7 +2820,8 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) struct VPaintData *vpd = paint_stroke_mode_data(stroke); ViewContext *vc = &vpd->vc; Object *ob = vc->obact; - + Mesh *me = ob->data; + ED_vpaint_proj_handle_free(vpd->vp_handle); MEM_freeN(vpd->indexar); @@ -2831,6 +2832,7 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) MEM_freeN(vpd->mlooptag); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DAG_id_tag_update(&me->id, 0); MEM_freeN(vpd); } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index b69547b0506..c0947dacbf0 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -239,6 +239,11 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const } } + if (fabsf(*max - *min) < 0.001f) { + *min -= 0.0005f; + *max += 0.0005f; + } + /* free memory */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 100329eddfc..7f4cd03c2fa 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -242,7 +242,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) if (params->display == FILE_DEFAULTDISPLAY) { if (U.uiflag & USER_SHOW_THUMBNAILS) { - if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE)) + if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) params->display = FILE_IMGDISPLAY; else params->display = FILE_SHORTDISPLAY; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index e1cd1da3a25..effcd80e1f0 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2393,7 +2393,9 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p continue; index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type); - RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); + if (index != -1) { /* Not all types are implemented yet... */ + RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); + } } RNA_enum_item_end(&item, &totitem); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index f22152651e2..a2db6827b0e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -177,7 +177,7 @@ void image_preview_event(int event) G.is_break = false; G.scene->nodetree->timecursor = set_timecursor; - G.scene->nodetree->test_break = blender_test_break; + G.scene->nodetree->test_break = BKE_blender_test_break; BIF_store_spare(); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 80dbfa140f6..ae5dcc4c73f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -149,6 +149,34 @@ static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac, c sima_zoom_set(sima, ar, sima->zoom * zoomfac, location); } +/** + * Fits the view to the bounds exactly, caller should add margin if needed. + */ +static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf *bounds) +{ + int image_size[2]; + float aspx, aspy; + + ED_space_image_get_size(sima, &image_size[0], &image_size[1]); + ED_space_image_get_aspect(sima, &aspx, &aspy); + + image_size[0] = image_size[0] * aspx; + image_size[1] = image_size[1] * aspy; + + /* adjust offset and zoom */ + sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]); + sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]); + + float size_xy[2], size; + size_xy[0] = BLI_rcti_size_x(&ar->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]); + size_xy[1] = BLI_rcti_size_y(&ar->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]); + + size = min_ff(size_xy[0], size_xy[1]); + CLAMP_MAX(size, 100.0f); + + sima_zoom_set(sima, ar, size, NULL); +} + #if 0 // currently unused static int image_poll(bContext *C) { @@ -763,8 +791,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene; Object *obedit; Image *ima; - float size, min[2], max[2], d[2], aspx, aspy; - int width, height; /* retrieve state */ sima = CTX_wm_space_image(C); @@ -773,33 +799,28 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) obedit = CTX_data_edit_object(C); ima = ED_space_image(sima); - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_aspect(sima, &aspx, &aspy); - - width = width * aspx; - height = height * aspy; /* get bounds */ + float min[2], max[2]; if (ED_space_image_show_uvedit(sima, obedit)) { - if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) + if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) { return OPERATOR_CANCELLED; + } } else if (ED_space_image_check_show_maskedit(scene, sima)) { if (!ED_mask_selected_minmax(C, min, max)) { return OPERATOR_CANCELLED; } } + rctf bounds = { + .xmin = min[0], .ymin = min[1], + .xmax = max[0], .ymax = max[1], + }; - /* adjust offset and zoom */ - sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width); - sima->yof = (int)(((min[1] + max[1]) * 0.5f - 0.5f) * height); + /* add some margin */ + BLI_rctf_scale(&bounds, 1.4f); - d[0] = max[0] - min[0]; - d[1] = max[1] - min[1]; - size = 0.5f * MAX2(d[0], d[1]) * MAX2(width, height) / 256.0f; - - if (size <= 0.01f) size = 0.01f; - sima_zoom_set(sima, ar, 0.7f / size, NULL); + sima_zoom_set_from_bounds(sima, ar, &bounds); ED_region_tag_redraw(ar); @@ -3140,7 +3161,7 @@ static int image_record_composite_apply(bContext *C, wmOperator *op) WM_cursor_time(CTX_wm_window(C), scene->r.cfra); - // XXX scene->nodetree->test_break = blender_test_break; + // XXX scene->nodetree->test_break = BKE_blender_test_break; // XXX scene->nodetree->test_break = NULL; BKE_image_all_free_anim_ibufs(scene->r.cfra); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index fe66750a9ec..6e156750815 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -45,7 +45,7 @@ #include "BLT_translation.h" #include "BKE_anim.h" -#include "BKE_blender.h" +#include "BKE_blender_version.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_DerivedMesh.h" diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index baf87f3fee5..a2159696394 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -2259,7 +2259,9 @@ static EnumPropertyItem *nla_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr continue; index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type); - RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); + if (index != -1) { /* Not all types are implemented yet... */ + RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); + } } RNA_enum_item_end(&item, &totitem); diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 0cbb7ea0220..9d1cf65b8ac 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -32,6 +32,7 @@ #include "DNA_node_types.h" #include "DNA_screen_types.h" +#include "BLI_array.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -420,6 +421,13 @@ static int ui_compatible_sockets(int typeA, int typeB) return (typeA == typeB); } +static int ui_node_item_name_compare(const void *a, const void *b) +{ + const bNodeType* type_a = *(const bNodeType**)a; + const bNodeType* type_b = *(const bNodeType**)b; + return BLI_natstrcmp(type_a->ui_name, type_b->ui_name); +} + static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) { bNodeTree *ntree = arg->ntree; @@ -439,7 +447,26 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) compatibility = NODE_OLD_SHADING; } + /* generate array of node types sorted by UI name */ + bNodeType **sorted_ntypes = NULL; + BLI_array_declare(sorted_ntypes); + NODE_TYPES_BEGIN(ntype) { + if (compatibility && !(ntype->compatibility & compatibility)) + continue; + + if (ntype->nclass != nclass) + continue; + + BLI_array_append(sorted_ntypes, ntype); + } + NODE_TYPES_END + + qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType*), ui_node_item_name_compare); + + /* generate UI */ + for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) { + bNodeType *ntype = sorted_ntypes[j]; NodeLinkItem *items; int totitems; char name[UI_MAX_NAME_STR]; @@ -447,12 +474,6 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) int i, num = 0; int icon = ICON_NONE; - if (compatibility && !(ntype->compatibility & compatibility)) - continue; - - if (ntype->nclass != nclass) - continue; - arg->node_type = ntype; ui_node_link_items(arg, SOCK_OUT, &items, &totitems); @@ -502,7 +523,8 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) if (items) MEM_freeN(items); } - NODE_TYPES_END + + BLI_array_free(sorted_ntypes); } static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name) diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 222fe27983c..2627b978b40 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -59,6 +59,7 @@ #include "ED_outliner.h" #include "ED_screen.h" #include "ED_keyframing.h" +#include "ED_armature.h" #include "WM_api.h" #include "WM_types.h" @@ -743,14 +744,35 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) TreeElement *te; int xdelta, ytop; - - // TODO: make this get this info from context instead... - if (OBACT == NULL) + + Object *obact = OBACT; + + if (!obact) return OPERATOR_CANCELLED; - - te = outliner_find_id(so, &so->tree, (ID *)OBACT); + + + te = outliner_find_id(so, &so->tree, &obact->id); + + if (obact->type == OB_ARMATURE) { + /* traverse down the bone hierarchy in case of armature */ + TreeElement *te_obact = te; + + if (obact->mode & OB_MODE_POSE) { + bPoseChannel *pchan = CTX_data_active_pose_bone(C); + if (pchan) { + te = outliner_find_posechannel(so, &te_obact->subtree, pchan); + } + } + else if (obact->mode & OB_MODE_EDIT) { + EditBone *ebone = CTX_data_active_bone(C); + if (ebone) { + te = outliner_find_editbone(so, &te_obact->subtree, ebone); + } + } + } + if (te) { - /* open up tree to active object */ + /* open up tree to active object/bone */ if (outliner_open_back(te)) { outliner_set_coordinates(ar, so); } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 3249c3f3ab7..155e41088d6 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -42,6 +42,8 @@ struct bContext; struct Scene; struct ID; struct Object; +struct bPoseChannel; +struct EditBone; typedef struct TreeElement { struct TreeElement *next, *prev, *parent; @@ -128,9 +130,11 @@ typedef enum { void outliner_free_tree(ListBase *lb); void outliner_cleanup_tree(struct SpaceOops *soops); -TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse); -TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem); -TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id); +TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse); +TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem); +TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id); +TreeElement *outliner_find_posechannel(struct SpaceOops *soops, ListBase *lb, const struct bPoseChannel *pchan); +TreeElement *outliner_find_editbone(struct SpaceOops *soops, ListBase *lb, const struct EditBone *ebone); struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode); void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SpaceOops *soops); diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 666179dd3c7..83d8519a7cb 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -198,7 +198,7 @@ void outliner_cleanup_tree(SpaceOops *soops) } /* Find specific item from the treestore */ -TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem) +TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem) { TreeElement *te, *tes; for (te = lb->first; te; te = te->next) { @@ -210,7 +210,7 @@ TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem) } /* tse is not in the treestore, we use its contents to find a match */ -TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) +TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse) { TreeStoreElem *tselem; @@ -225,25 +225,63 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) } /* Find treestore that refers to given ID */ -TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id) +TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id) { - TreeElement *te, *tes; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); if (tselem->type == 0) { - if (tselem->id == id) return te; + if (tselem->id == id) { + return te; + } /* only deeper on scene or object */ - if (te->idcode == ID_OB || te->idcode == ID_SCE || (soops->outlinevis == SO_GROUPS && te->idcode == ID_GR)) { - tes = outliner_find_id(soops, &te->subtree, id); - if (tes) return tes; + if (ELEM(te->idcode, ID_OB, ID_SCE) || + ((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR))) + { + TreeElement *tes = outliner_find_id(soops, &te->subtree, id); + if (tes) { + return tes; + } + } + } + } + return NULL; +} + +TreeElement *outliner_find_posechannel(SpaceOops *soops, ListBase *lb, const bPoseChannel *pchan) +{ + for (TreeElement *te = lb->first; te; te = te->next) { + if (te->directdata == pchan) { + return te; + } + + TreeStoreElem *tselem = TREESTORE(te); + if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) { + TreeElement *tes = outliner_find_posechannel(soops, &te->subtree, pchan); + if (tes) { + return tes; } } } return NULL; } +TreeElement *outliner_find_editbone(SpaceOops *soops, ListBase *lb, const EditBone *ebone) +{ + for (TreeElement *te = lb->first; te; te = te->next) { + if (te->directdata == ebone) { + return te; + } + + TreeStoreElem *tselem = TREESTORE(te); + if (ELEM(tselem->type, 0, TSE_EBONE)) { + TreeElement *tes = outliner_find_editbone(soops, &te->subtree, ebone); + if (tes) { + return tes; + } + } + } + return NULL; +} ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 08f2961d1b3..f636a07b064 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -5167,85 +5167,3 @@ void ED_view3D_lock_clear(View3D *v3d) v3d->ob_centre_cursor = false; v3d->flag2 &= ~V3D_LOCK_CAMERA; } - -/** - * Convenience function for snap ray-casting. - * - * Given a ray, cast it into the scene (snapping to faces). - * - * \return Snap success - */ -bool ED_view3d_snap_from_ray( - Scene *scene, - const float ray_start[3], const float ray_normal[3], - float r_co[3]) -{ - float r_no_dummy[3]; - float ray_dist = BVH_RAYCAST_DIST_MAX; - bool ret; - - struct Object *obedit = scene->obedit; - - /* try snap edge, then face if it fails */ - ret = snapObjectsRayEx( - scene, NULL, NULL, NULL, obedit, - NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, - ray_start, ray_normal, &ray_dist, - r_co, r_no_dummy, NULL, NULL, - NULL, NULL); - - return ret; -} - -/** - * Convenience function for performing snapping. - * - * Given a 2D region value, snap to vert/edge/face. - * - * \param mval: Screenspace coordinate. - * \param dist_px: Maximum distance to snap (in pixels). - * \param use_depth: Snap to the closest element, use when using more than one snap type. - * \param use_obedit: Use editmode cage. - * \param use_vert: Snap to verts. - * \param use_edge: Snap to edges. - * \param use_face: Snap to faces. - * \param r_co: hit location. - * \param r_no: hit normal (optional). - * \return Snap success - */ -bool ED_view3d_snap_from_region( - Scene *scene, View3D *v3d, ARegion *ar, - const float mval[2], float dist_px, - bool use_depth, bool use_obedit, - bool use_vert, bool use_edge, bool use_face, - float r_co[3], float r_no[3]) -{ - float r_no_dummy[3]; - float ray_dist = BVH_RAYCAST_DIST_MAX; - bool is_hit = false; - float *r_no_ptr = r_no ? r_no : r_no_dummy; - - struct Object *obedit = use_obedit ? scene->obedit : NULL; - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; - const bool elem_test[3] = {use_vert, use_edge, use_face}; - - BLI_assert(use_vert || use_edge || use_face); - - for (int i = 0; i < 3; i++) { - if (elem_test[i] && (is_hit == false || use_depth)) { - if (use_depth == false) { - ray_dist = BVH_RAYCAST_DIST_MAX; - } - if (snapObjectsEx( - scene, v3d, ar, NULL, obedit, - mval, SNAP_ALL, elem_type[i], - &ray_dist, - r_co, r_no_ptr, &dist_px)) - { - is_hit = true; - } - } - } - - return is_hit; -} diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index a5411da131b..c30e688f1e7 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -44,7 +44,7 @@ #include "BLI_utildefines.h" #include "BKE_appdir.h" -#include "BKE_blender.h" +#include "BKE_blender_copybuffer.h" #include "BKE_context.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 198cc3e5703..26eb707624a 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -46,6 +46,7 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "ED_transform.h" #include "ED_space_api.h" #include "BLF_api.h" @@ -109,6 +110,8 @@ typedef struct RulerInfo { int state; float drag_start_co[3]; + struct SnapObjectContext *snap_context; + /* wm state */ wmWindow *win; ScrArea *sa; @@ -128,6 +131,7 @@ static RulerItem *ruler_item_add(RulerInfo *ruler_info) static void ruler_item_remove(RulerInfo *ruler_info, RulerItem *ruler_item) { BLI_remlink(&ruler_info->items, ruler_item); + MEM_freeN(ruler_item); } @@ -632,6 +636,9 @@ static void view3d_ruler_end(const struct bContext *UNUSED(C), RulerInfo *ruler_ static void view3d_ruler_free(RulerInfo *ruler_info) { BLI_freelistN(&ruler_info->items); + + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + MEM_freeN(ruler_info); } @@ -642,11 +649,12 @@ static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], } /* use for mousemove events */ -static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, const int mval[2], - const bool do_thickness, const bool do_snap) +static bool view3d_ruler_item_mousemove( + RulerInfo *ruler_info, const int mval[2], + const bool do_thickness, const bool do_snap) { const float eps_bias = 0.0002f; - const float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ + float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ RulerItem *ruler_item = ruler_item_active_get(ruler_info); ruler_info->snap_flag &= ~RULER_SNAP_OK; @@ -657,8 +665,8 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons copy_v3_v3(co, ruler_info->drag_start_co); view3d_ruler_item_project(ruler_info, co, mval); if (do_thickness && ruler_item->co_index != 1) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = ruler_info->sa->spacedata.first; + // Scene *scene = CTX_data_scene(C); + // View3D *v3d = ruler_info->sa->spacedata.first; const float mval_fl[2] = {UNPACK2(mval)}; float ray_normal[3]; float ray_start[3]; @@ -666,33 +674,37 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons co_other = ruler_item->co[ruler_item->co_index == 0 ? 2 : 0]; - if (ED_view3d_snap_from_region( - scene, v3d, ruler_info->ar, - mval_fl, dist_px, - true, false, - false, false, true, + if (ED_transform_snap_object_project_view3d_mixed( + ruler_info->snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .snap_to_flag = SCE_SELECT_FACE, + }, + mval_fl, &dist_px, true, co, ray_normal)) { negate_v3(ray_normal); /* add some bias */ madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); - ED_view3d_snap_from_ray( - scene, - ray_start, ray_normal, - co_other); + ED_transform_snap_object_project_ray( + ruler_info->snap_context, + ray_start, ray_normal, NULL, + co_other, NULL); } } else if (do_snap) { - Scene *scene = CTX_data_scene(C); + // Scene *scene = CTX_data_scene(C); View3D *v3d = ruler_info->sa->spacedata.first; const float mval_fl[2] = {UNPACK2(mval)}; bool use_depth = (v3d->drawtype >= OB_SOLID); - if (ED_view3d_snap_from_region( - scene, v3d, ruler_info->ar, - mval_fl, dist_px, - use_depth, false, - true, true, use_depth, + if (ED_transform_snap_object_project_view3d_mixed( + ruler_info->snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .snap_to_flag = (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0), + }, + mval_fl, &dist_px, use_depth, co, NULL)) { ruler_info->snap_flag |= RULER_SNAP_OK; @@ -736,6 +748,10 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE op->customdata = ruler_info; + ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + ar, CTX_wm_view3d(C)); + ruler_info->win = win; ruler_info->sa = sa; ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel, @@ -818,7 +834,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) if (use_depth) { /* snap the first point added, not essential but handy */ ruler_item->co_index = 0; - view3d_ruler_item_mousemove(C, ruler_info, event->mval, false, true); + view3d_ruler_item_mousemove(ruler_info, event->mval, false, true); copy_v3_v3(ruler_info->drag_start_co, ruler_item->co[ruler_item->co_index]); } else { @@ -871,7 +887,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* update the new location */ - view3d_ruler_item_mousemove(C, ruler_info, event->mval, + view3d_ruler_item_mousemove(ruler_info, event->mval, event->shift != 0, event->ctrl != 0); do_draw = true; } @@ -920,7 +936,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: { if (ruler_info->state == RULER_STATE_DRAG) { - if (view3d_ruler_item_mousemove(C, ruler_info, event->mval, + if (view3d_ruler_item_mousemove(ruler_info, event->mval, event->shift != 0, event->ctrl != 0)) { do_draw = true; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 11623d06fff..fd7179d06dd 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -417,11 +417,12 @@ static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], cons for (base = vc->scene->base.first; base; base = base->next) { if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ - ED_view3d_project_base(vc->ar, base); - if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { - - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); - base->object->flag = base->flag; + if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { + if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { + + ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); + base->object->flag = base->flag; + } } if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) { do_lasso_select_pose(vc, base->object, mcords, moves, select); @@ -1093,20 +1094,22 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int /* two selection methods, the CTRL select uses max dist of 15 */ if (buffer) { - int a; - for (a = 0; a < hits; a++) { + for (int a = 0; a < hits; a++) { /* index was converted */ - if (base->selcol == buffer[(4 * a) + 3]) + if (base->selcol == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { ok = true; + break; + } } } else { - int temp, dist = 15; - ED_view3d_project_base(vc->ar, base); - - temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]); - if (temp < dist) - ok = true; + const int dist = 15 * U.pixelsize; + if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { + const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]}; + if (len_manhattan_v2_int(delta_px) < dist) { + ok = true; + } + } } if (ok) { @@ -1465,7 +1468,7 @@ static bool ed_object_select_pick( const bool has_bones = selectbuffer_has_bones(buffer, hits); /* note; shift+alt goes to group-flush-selecting */ - if (has_bones == 0 && enumerate) { + if (enumerate) { basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); } else { diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 7e1202aef77..73ec0f664da 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -306,6 +306,8 @@ typedef struct WalkInfo { float jump_height; /* maximum jump height */ float speed_factor; /* to use for fast/slow speeds */ + struct SnapObjectContext *snap_context; + struct View3DCameraControl *v3d_camera_control; } WalkInfo; @@ -402,12 +404,14 @@ static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk /** * \param r_distance Distance to the hit point */ -static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance) +static bool walk_floor_distance_get( + RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], + float *r_distance) { float ray_normal[3] = {0, 0, -1}; /* down */ float ray_start[3]; float r_location[3]; - float r_normal[3]; + float r_normal_dummy[3]; float dvec_tmp[3]; bool ret; @@ -418,12 +422,10 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); - ret = snapObjectsRayEx( - CTX_data_scene(C), NULL, NULL, NULL, NULL, - NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, + ret = ED_transform_snap_object_project_ray( + walk->snap_context, ray_start, ray_normal, r_distance, - r_location, r_normal, NULL, NULL, - NULL, NULL); + r_location, r_normal_dummy); /* artifically scale the distance to the scene size */ *r_distance /= walk->grid; @@ -435,34 +437,30 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w * \param r_location Location of the hit point * \param r_normal Normal of the hit surface, transformed to always face the camera */ -static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance) +static bool walk_ray_cast( + RegionView3D *rv3d, WalkInfo *walk, + float r_location[3], float r_normal[3], float *ray_distance) { - float ray_normal[3] = {0, 0, 1}; /* forward */ + float ray_normal[3] = {0, 0, -1}; /* forward */ float ray_start[3]; - float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ bool ret; *ray_distance = BVH_RAYCAST_DIST_MAX; copy_v3_v3(ray_start, rv3d->viewinv[3]); - copy_m3_m4(mat, rv3d->viewinv); - mul_m3_v3(mat, ray_normal); + mul_mat3_m4_v3(rv3d->viewinv, ray_normal); - mul_v3_fl(ray_normal, -1); normalize_v3(ray_normal); - ret = snapObjectsRayEx( - CTX_data_scene(C), NULL, NULL, NULL, NULL, - NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, - ray_start, ray_normal, ray_distance, - r_location, r_normal, NULL, NULL, - NULL, NULL); - + ret = ED_transform_snap_object_project_ray( + walk->snap_context, + ray_start, ray_normal, NULL, + r_location, r_normal); /* dot is positive if both rays are facing the same direction */ if (dot_v3v3(ray_normal, r_normal) > 0) { - copy_v3_fl3(r_normal, -r_normal[0], -r_normal[1], -r_normal[2]); + negate_v3(r_normal); } /* artifically scale the distance to the scene size */ @@ -575,6 +573,9 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; + walk->snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), walk->scene, SNAP_OBJECT_USE_CACHE, + walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( walk->scene, walk->v3d, walk->rv3d, @@ -625,6 +626,8 @@ static int walkEnd(bContext *C, WalkInfo *walk) ED_region_draw_cb_exit(walk->ar->type, walk->draw_handle_pixel); + ED_transform_snap_object_context_destroy(walk->snap_context); + ED_view3d_cameracontrol_release(walk->v3d_camera_control, walk->state == WALK_CANCEL); rv3d->rflag &= ~RV3D_NAVIGATING; @@ -897,7 +900,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent { float loc[3], nor[3]; float distance; - bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance); + bool ret = walk_ray_cast(walk->rv3d, walk, loc, nor, &distance); /* in case we are teleporting middle way from a jump */ walk->speed_jump = 0.0f; @@ -1178,7 +1181,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk) float difference = -100.0f; float fall_distance; - ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); + ret = walk_floor_distance_get(rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; @@ -1231,7 +1234,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk) if (t > walk->teleport.duration) { /* check to see if we are landing */ - ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); + ret = walk_floor_distance_get(rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index f3047c088a9..b7de49d8158 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC transform_ops.c transform_orientations.c transform_snap.c + transform_snap_object.c transform.h ) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 6d6a9aa90bc..3c69a1cd6c3 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -101,6 +101,11 @@ typedef struct TransSnap { * where the smallest absolute value defines whats closest. */ float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]); + + /** + * Re-usable snap context data. + */ + SnapObjectContext *object_context; } TransSnap; typedef struct TransCon { @@ -676,6 +681,7 @@ bool activeSnap(TransInfo *t); bool validSnap(TransInfo *t); void initSnapping(struct TransInfo *t, struct wmOperator *op); +void freeSnapping(struct TransInfo *t); void applyProject(TransInfo *t); void applyGridAbsolute(TransInfo *t); void applySnapping(TransInfo *t, float *vec); @@ -785,4 +791,8 @@ void projectVertSlideData(TransInfo *t, bool is_final); /* TODO. transform_queries.c */ bool checkUseAxisMatrix(TransInfo *t); +#define TRANSFORM_DIST_MAX_PX 1000.0f +#define TRANSFORM_SNAP_MAX_PX 100.0f +#define TRANSFORM_DIST_INVALID -FLT_MAX + #endif diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 63b3e5244e9..537e6e65dce 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1493,6 +1493,8 @@ void postTrans(bContext *C, TransInfo *t) if (t->mouse.data) { MEM_freeN(t->mouse.data); } + + freeSnapping(t); } void applyTransObjects(TransInfo *t) diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 70ac225c431..236a223b5ff 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -36,8 +36,6 @@ #include "PIL_time.h" -#include "DNA_armature_types.h" -#include "DNA_curve_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_meshdata_types.h" /* Temporary, for snapping to other unselected meshes */ @@ -61,13 +59,11 @@ #include "BKE_editmesh.h" #include "BKE_sequencer.h" #include "BKE_main.h" -#include "BKE_tracking.h" #include "RNA_access.h" #include "WM_types.h" -#include "ED_armature.h" #include "ED_image.h" #include "ED_node.h" #include "ED_uvedit.h" @@ -83,10 +79,6 @@ /* this should be passed as an arg for use in snap functions */ #undef BASACT -#define TRANSFORM_DIST_MAX_PX 1000.0f -#define TRANSFORM_SNAP_MAX_PX 100.0f -#define TRANSFORM_DIST_INVALID -FLT_MAX - /* use half of flt-max so we can scale up without an exception */ /********************* PROTOTYPES ***********************/ @@ -331,8 +323,8 @@ void applyProject(TransInfo *t) if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { if (snapObjectsTransform( - t, mval_fl, t->tsnap.modeSelect, - loc, no, &dist_px)) + t, mval_fl, t->tsnap.modeSelect, &dist_px, + loc, no)) { // if (t->flag & (T_EDIT|T_POSE)) { // mul_m4_v3(imat, loc); @@ -565,6 +557,14 @@ static void initSnappingMode(TransInfo *t) /* Always grid outside of 3D view */ t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; } + + if (t->flag & (T_OBJECT | T_EDIT)) { + if (t->spacetype == SPACE_VIEW3D) { + t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( + G.main, t->scene, SNAP_OBJECT_USE_CACHE, + t->ar, t->view); + } + } } void initSnapping(TransInfo *t, wmOperator *op) @@ -628,6 +628,14 @@ void initSnapping(TransInfo *t, wmOperator *op) initSnappingMode(t); } +void freeSnapping(TransInfo *t) +{ + if (t->tsnap.object_context) { + ED_transform_snap_object_context_destroy(t->tsnap.object_context); + t->tsnap.object_context = NULL; + } +} + static void setSnappingCallback(TransInfo *t) { t->tsnap.calcSnap = CalcSnapGeometry; @@ -994,8 +1002,8 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) else { zero_v3(no); /* objects won't set this */ found = snapObjectsTransform( - t, mval, t->tsnap.modeSelect, - loc, no, &dist_px); + t, mval, t->tsnap.modeSelect, &dist_px, + loc, no); } if (found == true) { @@ -1229,869 +1237,26 @@ static void TargetSnapClosest(TransInfo *t) } } -static bool snapEdge( - ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px) -{ - float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; - int result; - bool retval = false; - - copy_v3_v3(ray_end, ray_normal_local); - mul_v3_fl(ray_end, 2000); - add_v3_v3v3(ray_end, ray_start_local, ray_end); - - result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */ - - if (result) { - float edge_loc[3], vec[3]; - float mul; - - /* check for behind ray_start */ - sub_v3_v3v3(dvec, intersect, ray_start_local); - - sub_v3_v3v3(edge_loc, v1co, v2co); - sub_v3_v3v3(vec, intersect, v2co); - - mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); - - if (mul > 1) { - mul = 1; - copy_v3_v3(intersect, v1co); - } - else if (mul < 0) { - mul = 0; - copy_v3_v3(intersect, v2co); - } - - if (dot_v3v3(ray_normal_local, dvec) > 0) { - float location[3]; - float new_depth; - float screen_loc[2]; - float new_dist; - - copy_v3_v3(location, intersect); - - mul_m4_v3(obmat, location); - - new_depth = len_v3v3(location, ray_start); - - if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - new_dist = len_manhattan_v2v2(mval_fl, screen_loc); - } - else { - new_dist = TRANSFORM_DIST_MAX_PX; - } - - /* 10% threshold if edge is closer but a bit further - * this takes care of series of connected edges a bit slanted w.r.t the viewport - * otherwise, it would stick to the verts of the closest edge and not slide along merrily - * */ - if (new_dist <= *r_dist_px && new_depth < *ray_depth * 1.001f) { - float n1[3], n2[3]; - - *ray_depth = new_depth; - retval = true; - - sub_v3_v3v3(edge_loc, v1co, v2co); - sub_v3_v3v3(vec, intersect, v2co); - - mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); - - if (r_no) { - normal_short_to_float_v3(n1, v1no); - normal_short_to_float_v3(n2, v2no); - interp_v3_v3v3(r_no, n2, n1, mul); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - - copy_v3_v3(r_loc, location); - - *r_dist_px = new_dist; - } - } - } - - return retval; -} - -static bool snapVertex( - ARegion *ar, const float vco[3], const short vno[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px) -{ - bool retval = false; - float dvec[3]; - - sub_v3_v3v3(dvec, vco, ray_start_local); - - if (dot_v3v3(ray_normal_local, dvec) > 0) { - float location[3]; - float new_depth; - float screen_loc[2]; - float new_dist; - - copy_v3_v3(location, vco); - - mul_m4_v3(obmat, location); - - new_depth = len_v3v3(location, ray_start); - - if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - new_dist = len_manhattan_v2v2(mval_fl, screen_loc); - } - else { - new_dist = TRANSFORM_DIST_MAX_PX; - } - - - if (new_dist <= *r_dist_px && new_depth < *ray_depth) { - *ray_depth = new_depth; - retval = true; - - copy_v3_v3(r_loc, location); - - if (r_no) { - normal_short_to_float_v3(r_no, vno); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - - *r_dist_px = new_dist; - } - } - - return retval; -} - -static bool snapArmature( - ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], - const float mval[2], const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - float r_loc[3], float *UNUSED(r_no), float *r_dist_px) -{ - float imat[4][4]; - float ray_start_local[3], ray_normal_local[3]; - bool retval = false; - - invert_m4_m4(imat, obmat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - - if (arm->edbo) { - EditBone *eBone; - - for (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 |= snapVertex(ar, eBone->head, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - break; - case SCE_SNAP_MODE_EDGE: - retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - break; - } - } - } - } - } - 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; - /* skip hidden bones */ - if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { - const float *head_vec = pchan->pose_head; - const float *tail_vec = pchan->pose_tail; - - switch (snap_to) { - case SCE_SNAP_MODE_VERTEX: - retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - break; - case SCE_SNAP_MODE_EDGE: - retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - break; - } - } - } - } - - return retval; -} - -static bool snapCurve( - ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], - const float mval[2], const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - float r_loc[3], float *UNUSED(r_no), float *r_dist_px) -{ - float imat[4][4]; - float ray_start_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_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); - - 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++) { - switch (snap_to) { - case SCE_SNAP_MODE_VERTEX: - { - if (ob->mode == OB_MODE_EDIT) { - if (nu->bezt) { - /* don't snap to selected (moving) or hidden */ - if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { - break; - } - retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - /* 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 |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - } - if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { - retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - } - } - else { - /* don't snap to selected (moving) or hidden */ - if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { - break; - } - retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - } - } - else { - /* curve is not visible outside editmode if nurb length less than two */ - if (nu->pntsu > 1) { - if (nu->bezt) { - retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - } - else { - retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); - } - } - } - break; - } - default: - break; - } - } - } - return retval; -} - -static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) -{ - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; -} - -static bool snapDerivedMesh( - ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], - const float mval[2], const short snap_to, bool do_bb, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index) -{ - bool retval = false; - int totvert = dm->getNumVerts(dm); - - if (totvert > 0) { - const bool do_ray_start_correction = ( - ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && - (ar && !((RegionView3D *)ar->regiondata)->is_persp)); - bool need_ray_start_correction_init = do_ray_start_correction; - - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - float local_scale, local_depth, len_diff; - - BVHTreeFromMesh treedata = {0}; - - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); - - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); - - /* local scale in normal direction */ - local_scale = normalize_v3(ray_normal_local); - local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } - - if (do_bb) { - BoundBox *bb = BKE_object_boundbox_get(ob); - - if (bb) { - BoundBox bb_temp; - - /* We cannot aford a bbox with some null dimension, which may happen in some cases... - * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ - bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); - - /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'r_dist_px'), - * scale up so we can snap against verts & edges on the boundbox, see T46816. */ - if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { - BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f); - bb = &bb_temp; - } - - /* was local_depth, see: T47838 */ - len_diff = BVH_RAYCAST_DIST_MAX; - - if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) { - return retval; - } - need_ray_start_correction_init = false; - } - } - - treedata.em_evil = em; - treedata.em_evil_all = false; - switch (snap_to) { - case SCE_SNAP_MODE_FACE: - bvhtree_from_mesh_looptri(&treedata, dm, 0.0f, 4, 6); - break; - case SCE_SNAP_MODE_VERTEX: - bvhtree_from_mesh_verts(&treedata, dm, 0.0f, 2, 6); - break; - } - - 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. - */ - BVHTreeNearest nearest; - - if (treedata.tree != NULL) { - 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) { - len_diff = sqrtf(nearest.dist_sq); - } - } - } - /* 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 (do_ray_start_correction) { - 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 - len_v3v3(ray_start_local, ray_org_local)); - local_depth -= len_diff; - } - else { - len_diff = 0.0f; - } - - switch (snap_to) { - case SCE_SNAP_MODE_FACE: - { - BVHTreeRayHit hit; - - hit.index = -1; - hit.dist = local_depth; - - if (treedata.tree && - BLI_bvhtree_ray_cast(treedata.tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata.raycast_callback, &treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - 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); - - retval = true; - - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata.looptri[hit.index]); - } - } - } - break; - } - case SCE_SNAP_MODE_VERTEX: - { - BVHTreeNearest nearest; - - nearest.index = -1; - nearest.dist_sq = local_depth * local_depth; - if (treedata.tree && - BLI_bvhtree_find_nearest_to_ray( - treedata.tree, ray_start_local, ray_normal_local, - &nearest, NULL, NULL) != -1) - { - const MVert *v = &treedata.vert[nearest.index]; - retval = snapVertex( - ar, v->co, v->no, obmat, timat, mval, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no, r_dist_px); - } - break; - } - case SCE_SNAP_MODE_EDGE: - { - MVert *verts = dm->getVertArray(dm); - MEdge *edges = dm->getEdgeArray(dm); - int totedge = dm->getNumEdges(dm); - const int *index_array = NULL; - int index = 0; - int i; - - if (em != NULL) { - index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); - BM_mesh_elem_table_ensure(em->bm, BM_EDGE); - } - - for (i = 0; i < totedge; i++) { - MEdge *e = edges + i; - bool test = true; - - if (em != NULL) { - if (index_array) { - index = index_array[i]; - } - else { - index = i; - } - - if (index == ORIGINDEX_NONE) { - test = false; - } - else { - BMEdge *eed = BM_edge_at_index(em->bm, index); - - if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) || - BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) - { - test = false; - } - } - } - - if (test) { - retval |= snapEdge( - ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat, - mval, ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no, r_dist_px); - } - } - - break; - } - } - - free_bvhtree_from_mesh(&treedata); - } - - return retval; -} - -/* may extend later (for now just snaps to empty center) */ -static bool snapEmpty( - ARegion *ar, Object *ob, float obmat[4][4], - const float mval[2], const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - float r_loc[3], float *UNUSED(r_no), float *r_dist_px) -{ - float imat[4][4]; - float ray_start_local[3], ray_normal_local[3]; - bool retval = false; - - if (ob->transflag & OB_DUPLI) { - return retval; - } - /* for now only vertex supported */ - if (snap_to != SCE_SNAP_MODE_VERTEX) { - return retval; - } - - invert_m4_m4(imat, obmat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - - switch (snap_to) { - case SCE_SNAP_MODE_VERTEX: - { - const float zero_co[3] = {0.0f}; - retval |= snapVertex( - ar, zero_co, NULL, obmat, NULL, mval, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL, r_dist_px); - break; - } - default: - break; - } - - return retval; -} - -static bool snapCamera( - ARegion *ar, Scene *scene, Object *object, float obmat[4][4], - const float mval[2], const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - float r_loc[3], float *UNUSED(r_no), float *r_dist_px) -{ - 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_start_local[3], ray_normal_local[3]; - - if (clip == NULL) { - return retval; - } - if (object->transflag & OB_DUPLI) { - return retval; - } - - tracking = &clip->tracking; - - BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); - - invert_m4_m4(orig_camera_imat, orig_camera_mat); - invert_m4_m4(imat, obmat); - - switch (snap_to) { - case SCE_SNAP_MODE_VERTEX: - { - MovieTrackingObject *tracking_object; - - for (tracking_object = tracking->objects.first; - tracking_object; - tracking_object = tracking_object->next) - { - ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); - MovieTrackingTrack *track; - float reconstructed_camera_mat[4][4], - reconstructed_camera_imat[4][4]; - float (*vertex_obmat)[4]; - - copy_v3_v3(ray_start_local, ray_start); - 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); - - invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat); - } - - for (track = tracksbase->first; track; track = track->next) { - float bundle_pos[3]; - - if ((track->flag & TRACK_HAS_BUNDLE) == 0) { - continue; - } - - copy_v3_v3(bundle_pos, track->bundle_pos); - if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - mul_m4_v3(orig_camera_imat, ray_start_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_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); - vertex_obmat = obmat; - } - - retval |= snapVertex( - ar, bundle_pos, NULL, vertex_obmat, NULL, mval, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL, r_dist_px); - } - } - - break; - } - default: - break; - } - - return retval; -} - -static bool snapObject( - Scene *scene, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit, - const float mval[2], const short snap_to, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, - Object **r_ob, float r_obmat[4][4]) -{ - bool retval = false; - - if (ob->type == OB_MESH) { - BMEditMesh *em; - DerivedMesh *dm; - bool do_bb = true; - - if (use_obedit) { - em = BKE_editmesh_from_object(ob); - dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); - do_bb = false; - } - else { - /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. - * still set the 'em' to NULL, since we only want the 'dm'. */ - em = BKE_editmesh_from_object(ob); - if (em) { - editbmesh_get_derived_cage_and_final(scene, ob, em, CD_MASK_BAREMESH, &dm); - } - else { - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - } - em = NULL; - } - - retval = snapDerivedMesh( - ar, ob, dm, em, obmat, mval, snap_to, do_bb, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_dist_px, r_index); - - dm->release(dm); - } - else if (ob->type == OB_ARMATURE) { - retval = snapArmature( - ar, ob, ob->data, obmat, mval, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no, r_dist_px); - } - else if (ob->type == OB_CURVE) { - retval = snapCurve( - ar, ob, ob->data, obmat, mval, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no, r_dist_px); - } - else if (ob->type == OB_EMPTY) { - retval = snapEmpty( - ar, ob, obmat, mval, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no, r_dist_px); - } - else if (ob->type == OB_CAMERA) { - retval = snapCamera( - ar, scene, ob, obmat, mval, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no, r_dist_px); - } - - if (retval) { - if (r_ob) { - *r_ob = ob; - copy_m4_m4(r_obmat, obmat); - } - } - - return retval; -} - -static bool snapObjectsRay( - Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_to, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, - Object **r_ob, float r_obmat[4][4]) -{ - Base *base; - bool retval = false; - - if (snap_select == SNAP_ALL && obedit) { - Object *ob = obedit; - - retval |= snapObject( - scene, ar, ob, ob->obmat, true, - mval, snap_to, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); - } - - for (base = FIRSTBASE; base != NULL; base = base->next) { - if ((BASE_VISIBLE_BGMODE(v3d, scene, base)) && - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - - ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || - (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act))) - { - Object *ob = base->object; - Object *ob_snap = ob; - bool use_obedit = false; - - /* for linked objects, use the same object but a different matrix */ - if (obedit && ob->data == obedit->data) { - use_obedit = true; - ob_snap = obedit; - } - - if (ob->transflag & OB_DUPLI) { - DupliObject *dupli_ob; - ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); - - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data); - Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; - - retval |= snapObject( - scene, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli, - mval, snap_to, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); - } - - free_object_duplilist(lb); - } - - retval |= snapObject( - scene, ar, ob_snap, ob->obmat, use_obedit, - mval, snap_to, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); - } - } - - return retval; -} -static bool snapObjects( - Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_to, - float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index) -{ - float ray_start[3], ray_normal[3], ray_orgigin[3]; - - if (!ED_view3d_win_to_ray_ex(ar, v3d, mval, ray_orgigin, ray_normal, ray_start, true)) { - return false; - } - - return snapObjectsRay( - scene, v3d, ar, base_act, obedit, - mval, snap_select, snap_to, - ray_start, ray_normal, ray_orgigin, ray_depth, - r_loc, r_no, r_dist_px, r_index, NULL, NULL); -} - bool snapObjectsTransform( TransInfo *t, const float mval[2], SnapSelect snap_select, - float r_loc[3], float r_no[3], float *r_dist_px) + float *dist_px, + float r_loc[3], float r_no[3]) { float ray_dist = BVH_RAYCAST_DIST_MAX; - Object *obedit = NULL; - Base *base_act = NULL; - - if (t->flag & T_EDIT) { - obedit = t->obedit; - } - if ((t->options & CTX_GPENCIL_STROKES) == 0) { - base_act = t->scene->basact; - } - - return snapObjects( - t->scene, t->view, t->ar, base_act, obedit, - mval, snap_select, t->scene->toolsettings->snap_mode, + return ED_transform_snap_object_project_view3d_ex( + t->tsnap.object_context, + &(const struct SnapObjectParams){ + .snap_select = snap_select, + .snap_to = t->scene->toolsettings->snap_mode, + .use_object_edit = (t->flag & T_EDIT) != 0, + .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0, + }, + mval, dist_px, &ray_dist, - r_loc, r_no, r_dist_px, NULL); + r_loc, r_no, NULL); } -bool snapObjectsContext( - bContext *C, const float mval[2], SnapSelect snap_select, - float r_loc[3], float r_no[3], float *r_dist_px) -{ - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - Object *obedit = CTX_data_edit_object(C); - float ray_dist = BVH_RAYCAST_DIST_MAX; - - return snapObjects( - scene, v3d, ar, scene->basact, obedit, - mval, snap_select, scene->toolsettings->snap_mode, - &ray_dist, - r_loc, r_no, r_dist_px, NULL); -} - -bool snapObjectsEx( - Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_to, - float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px) -{ - return snapObjects( - scene, v3d, ar, base_act, obedit, - mval, snap_select, snap_to, - ray_depth, - r_loc, r_no, r_dist_px, NULL); -} -bool snapObjectsRayEx( - Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, - const float mval[2], SnapSelect snap_select, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, - Object **r_ob, float r_obmat[4][4]) -{ - return snapObjectsRay( - scene, v3d, ar, base_act, obedit, - mval, snap_select, snap_to, - ray_start, ray_normal, ray_start, ray_depth, - r_loc, r_no, r_dist_px, r_index, - r_ob, r_obmat); -} /******************** PEELING *********************************/ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c new file mode 100644 index 00000000000..e9209eea0e7 --- /dev/null +++ b/source/blender/editors/transform/transform_snap_object.c @@ -0,0 +1,1207 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/transform/transform_snap_object.c + * \ingroup edtransform + */ + +#include <stdlib.h> +#include <math.h> +#include <float.h> +#include <stdio.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_kdopbvh.h" +#include "BLI_memarena.h" +#include "BLI_ghash.h" +#include "BLI_utildefines.h" + +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_object.h" +#include "BKE_anim.h" /* for duplis */ +#include "BKE_editmesh.h" +#include "BKE_main.h" +#include "BKE_tracking.h" + +#include "ED_transform.h" +#include "ED_view3d.h" +#include "ED_armature.h" + +#include "transform.h" + +typedef struct SnapObjectData { + BVHTreeFromMesh *bvh_trees[2]; +} SnapObjectData; + + +struct SnapObjectContext { + Main *bmain; + Scene *scene; + int flag; + + /* Optional: when performing screen-space projection. + * otherwise this doesn't take viewport into account. */ + bool use_v3d; + struct { + struct View3D *v3d; + struct ARegion *ar; + } v3d_data; + + + /* Object -> SnapObjectData map */ + struct { + GHash *object_map; + MemArena *mem_arena; + } cache; + +}; + +/* -------------------------------------------------------------------- */ + +/** \name Internal Object Snapping API + * \{ */ + +static bool snapEdge( + ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + float r_loc[3], float r_no[3]) +{ + float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; + int result; + bool retval = false; + + copy_v3_v3(ray_end, ray_normal_local); + mul_v3_fl(ray_end, 2000); + add_v3_v3v3(ray_end, ray_start_local, ray_end); + + /* dvec used but we don't care about result */ + result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); + + if (result) { + float edge_loc[3], vec[3]; + float mul; + + /* check for behind ray_start */ + sub_v3_v3v3(dvec, intersect, ray_start_local); + + sub_v3_v3v3(edge_loc, v1co, v2co); + sub_v3_v3v3(vec, intersect, v2co); + + mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); + + if (mul > 1) { + mul = 1; + copy_v3_v3(intersect, v1co); + } + else if (mul < 0) { + mul = 0; + copy_v3_v3(intersect, v2co); + } + + if (dot_v3v3(ray_normal_local, dvec) > 0) { + float location[3]; + float new_depth; + float screen_loc[2]; + float new_dist; + + copy_v3_v3(location, intersect); + + mul_m4_v3(obmat, location); + + new_depth = len_v3v3(location, ray_start); + + if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + new_dist = len_manhattan_v2v2(mval_fl, screen_loc); + } + else { + new_dist = TRANSFORM_DIST_MAX_PX; + } + + /* 10% threshold if edge is closer but a bit further + * this takes care of series of connected edges a bit slanted w.r.t the viewport + * otherwise, it would stick to the verts of the closest edge and not slide along merrily + * */ + if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) { + float n1[3], n2[3]; + + *ray_depth = new_depth; + retval = true; + + sub_v3_v3v3(edge_loc, v1co, v2co); + sub_v3_v3v3(vec, intersect, v2co); + + mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); + + if (r_no) { + normal_short_to_float_v3(n1, v1no); + normal_short_to_float_v3(n2, v2no); + interp_v3_v3v3(r_no, n2, n1, mul); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + + copy_v3_v3(r_loc, location); + + *dist_px = new_dist; + } + } + } + + return retval; +} + +static bool snapVertex( + ARegion *ar, const float vco[3], const short vno[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + float r_loc[3], float r_no[3]) +{ + bool retval = false; + float dvec[3]; + + sub_v3_v3v3(dvec, vco, ray_start_local); + + if (dot_v3v3(ray_normal_local, dvec) > 0) { + float location[3]; + float new_depth; + float screen_loc[2]; + float new_dist; + + copy_v3_v3(location, vco); + + mul_m4_v3(obmat, location); + + new_depth = len_v3v3(location, ray_start); + + if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + new_dist = len_manhattan_v2v2(mval_fl, screen_loc); + } + else { + new_dist = TRANSFORM_DIST_MAX_PX; + } + + + if (new_dist <= *dist_px && new_depth < *ray_depth) { + *ray_depth = new_depth; + retval = true; + + copy_v3_v3(r_loc, location); + + if (r_no) { + normal_short_to_float_v3(r_no, vno); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + + *dist_px = new_dist; + } + } + + return retval; +} + +static bool snapArmature( + ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no)) +{ + float imat[4][4]; + float ray_start_local[3], ray_normal_local[3]; + bool retval = false; + + invert_m4_m4(imat, obmat); + + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + + if (arm->edbo) { + EditBone *eBone; + + for (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 |= snapVertex( + ar, eBone->head, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + retval |= snapVertex( + ar, eBone->tail, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + break; + case SCE_SNAP_MODE_EDGE: + retval |= snapEdge( + ar, eBone->head, NULL, eBone->tail, NULL, + obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, + ray_depth, r_loc, NULL); + break; + } + } + } + } + } + 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; + /* skip hidden bones */ + if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { + const float *head_vec = pchan->pose_head; + const float *tail_vec = pchan->pose_tail; + + switch (snap_to) { + case SCE_SNAP_MODE_VERTEX: + retval |= snapVertex( + ar, head_vec, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, + ray_depth, r_loc, NULL); + retval |= snapVertex( + ar, tail_vec, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + break; + case SCE_SNAP_MODE_EDGE: + retval |= snapEdge( + ar, head_vec, NULL, tail_vec, NULL, + obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, + ray_depth, r_loc, NULL); + break; + } + } + } + } + + return retval; +} + +static bool snapCurve( + ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no)) +{ + float imat[4][4]; + float ray_start_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_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + 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++) { + switch (snap_to) { + case SCE_SNAP_MODE_VERTEX: + { + if (ob->mode == OB_MODE_EDIT) { + if (nu->bezt) { + /* don't snap to selected (moving) or hidden */ + if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { + break; + } + retval |= snapVertex( + ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + /* 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 |= snapVertex( + ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + if (!(nu->bezt[u].f3 & SELECT) && + !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) + { + retval |= snapVertex( + ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + } + else { + /* don't snap to selected (moving) or hidden */ + if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { + break; + } + retval |= snapVertex( + ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + } + else { + /* curve is not visible outside editmode if nurb length less than two */ + if (nu->pntsu > 1) { + if (nu->bezt) { + retval |= snapVertex( + ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + else { + retval |= snapVertex( + ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + } + } + break; + } + default: + break; + } + } + } + return retval; +} + +/* may extend later (for now just snaps to empty center) */ +static bool snapEmpty( + ARegion *ar, Object *ob, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no)) +{ + float imat[4][4]; + float ray_start_local[3], ray_normal_local[3]; + bool retval = false; + + if (ob->transflag & OB_DUPLI) { + return retval; + } + /* for now only vertex supported */ + if (snap_to != SCE_SNAP_MODE_VERTEX) { + return retval; + } + + invert_m4_m4(imat, obmat); + + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + + switch (snap_to) { + case SCE_SNAP_MODE_VERTEX: + { + const float zero_co[3] = {0.0f}; + retval |= snapVertex( + ar, zero_co, NULL, obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + break; + } + default: + break; + } + + return retval; +} + +static bool snapCamera( + ARegion *ar, Scene *scene, Object *object, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no)) +{ + 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_start_local[3], ray_normal_local[3]; + + if (clip == NULL) { + return retval; + } + if (object->transflag & OB_DUPLI) { + return retval; + } + + tracking = &clip->tracking; + + BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); + + invert_m4_m4(orig_camera_imat, orig_camera_mat); + invert_m4_m4(imat, obmat); + + switch (snap_to) { + case SCE_SNAP_MODE_VERTEX: + { + MovieTrackingObject *tracking_object; + + for (tracking_object = tracking->objects.first; + tracking_object; + tracking_object = tracking_object->next) + { + ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); + MovieTrackingTrack *track; + float reconstructed_camera_mat[4][4], + reconstructed_camera_imat[4][4]; + float (*vertex_obmat)[4]; + + copy_v3_v3(ray_start_local, ray_start); + 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); + + invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat); + } + + for (track = tracksbase->first; track; track = track->next) { + float bundle_pos[3]; + + if ((track->flag & TRACK_HAS_BUNDLE) == 0) { + continue; + } + + copy_v3_v3(bundle_pos, track->bundle_pos); + if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { + mul_m4_v3(orig_camera_imat, ray_start_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_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + vertex_obmat = obmat; + } + + retval |= snapVertex( + ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL); + } + } + + break; + } + default: + break; + } + + return retval; +} + +static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) +{ + const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; +} + +static bool snapDerivedMesh( + SnapObjectContext *sctx, + Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, bool do_bb, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + float r_loc[3], float r_no[3], int *r_index) +{ + ARegion *ar = sctx->v3d_data.ar; + bool retval = false; + int totvert = dm->getNumVerts(dm); + + if (totvert > 0) { + const bool do_ray_start_correction = ( + ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && + (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); + bool need_ray_start_correction_init = do_ray_start_correction; + + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + float local_scale, local_depth, len_diff; + + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + /* local scale in normal direction */ + local_scale = normalize_v3(ray_normal_local); + local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + SnapObjectData *sod = NULL; + + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*sod)); + memset(sod, 0, sizeof(*sod)); + } + } + + if (do_bb) { + BoundBox *bb = BKE_object_boundbox_get(ob); + + if (bb) { + BoundBox bb_temp; + + /* We cannot aford a bbox with some null dimension, which may happen in some cases... + * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ + bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); + + /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'), + * scale up so we can snap against verts & edges on the boundbox, see T46816. */ + if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { + BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f); + bb = &bb_temp; + } + + /* was local_depth, see: T47838 */ + len_diff = BVH_RAYCAST_DIST_MAX; + + if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) { + return retval; + } + need_ray_start_correction_init = false; + } + } + + BVHTreeFromMesh *treedata = NULL, treedata_stack; + + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + int tree_index = -1; + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + tree_index = 1; + break; + case SCE_SNAP_MODE_VERTEX: + tree_index = 0; + break; + } + if (tree_index != -1) { + if (sod->bvh_trees[tree_index] == NULL) { + sod->bvh_trees[tree_index] = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*treedata)); + } + treedata = sod->bvh_trees[tree_index]; + } + } + else { + if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); + } + } + + if (treedata) { + treedata->em_evil = em; + treedata->em_evil_all = false; + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); + break; + case SCE_SNAP_MODE_VERTEX: + bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); + break; + } + } + + 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) { + len_diff = sqrtf(nearest.dist_sq); + } + } + } + /* 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 (do_ray_start_correction) { + 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 - len_v3v3(ray_start_local, ray_org_local)); + local_depth -= len_diff; + } + else { + len_diff = 0.0f; + } + + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + { + BVHTreeRayHit hit; + + hit.index = -1; + hit.dist = local_depth; + + if (treedata->tree && + BLI_bvhtree_ray_cast(treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + 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); + + retval = true; + + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + } + } + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist_sq = local_depth * local_depth; + if (treedata->tree && + BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_start_local, ray_normal_local, + &nearest, NULL, NULL) != -1) + { + const MVert *v = &treedata->vert[nearest.index]; + retval = snapVertex( + ar, v->co, v->no, obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); + } + break; + } + case SCE_SNAP_MODE_EDGE: + { + MVert *verts = dm->getVertArray(dm); + MEdge *edges = dm->getEdgeArray(dm); + int totedge = dm->getNumEdges(dm); + const int *index_array = NULL; + int index = 0; + int i; + + if (em != NULL) { + index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + } + + for (i = 0; i < totedge; i++) { + MEdge *e = edges + i; + bool test = true; + + if (em != NULL) { + if (index_array) { + index = index_array[i]; + } + else { + index = i; + } + + if (index == ORIGINDEX_NONE) { + test = false; + } + else { + BMEdge *eed = BM_edge_at_index(em->bm, index); + + if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) || + BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) + { + test = false; + } + } + } + + if (test) { + retval |= snapEdge( + ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, + obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); + } + } + + break; + } + } + + if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { + if (treedata) { + free_bvhtree_from_mesh(treedata); + } + } + } + + return retval; +} + +static bool snapObject( + SnapObjectContext *sctx, + Object *ob, float obmat[4][4], bool use_obedit, const short snap_to, + const float mval[2], float *dist_px, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + Object **r_ob, float r_obmat[4][4]) +{ + ARegion *ar = sctx->v3d_data.ar; + bool retval = false; + + if (ob->type == OB_MESH) { + BMEditMesh *em; + DerivedMesh *dm; + bool do_bb = true; + + if (use_obedit) { + em = BKE_editmesh_from_object(ob); + dm = editbmesh_get_derived_cage(sctx->scene, ob, em, CD_MASK_BAREMESH); + do_bb = false; + } + else { + /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. + * still set the 'em' to NULL, since we only want the 'dm'. */ + em = BKE_editmesh_from_object(ob); + if (em) { + editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); + } + else { + dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); + } + em = NULL; + } + + retval = snapDerivedMesh( + sctx, ob, dm, em, obmat, mval, dist_px, snap_to, do_bb, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index); + + dm->release(dm); + } + else if (ob->type == OB_ARMATURE) { + retval = snapArmature( + ar, ob, ob->data, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no); + } + else if (ob->type == OB_CURVE) { + retval = snapCurve( + ar, ob, ob->data, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no); + } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty( + ar, ob, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no); + } + else if (ob->type == OB_CAMERA) { + retval = snapCamera( + ar, sctx->scene, ob, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no); + } + + if (retval) { + if (r_ob) { + *r_ob = ob; + copy_m4_m4(r_obmat, obmat); + } + } + + return retval; +} + +static bool snapObjectsRay( + SnapObjectContext *sctx, + SnapSelect snap_select, const short snap_to, + const float mval[2], float *dist_px, + /* special handling of active and edit objects */ + Base *base_act, Object *obedit, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + Object **r_ob, float r_obmat[4][4]) +{ + Base *base; + bool retval = false; + + if (snap_select == SNAP_ALL && obedit) { + Object *ob = obedit; + + retval |= snapObject( + sctx, ob, ob->obmat, true, snap_to, + mval, dist_px, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index, r_ob, r_obmat); + } + + for (base = sctx->scene->base.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && + (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + + ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || + (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act))) + { + Object *ob = base->object; + Object *ob_snap = ob; + bool use_obedit = false; + + /* for linked objects, use the same object but a different matrix */ + if (obedit && ob->data == obedit->data) { + use_obedit = true; + ob_snap = obedit; + } + + if (ob->transflag & OB_DUPLI) { + DupliObject *dupli_ob; + ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob); + + for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data); + Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; + + retval |= snapObject( + sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to, + mval, dist_px, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index, r_ob, r_obmat); + } + + free_object_duplilist(lb); + } + + retval |= snapObject( + sctx, ob_snap, ob->obmat, use_obedit, snap_to, + mval, dist_px, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index, r_ob, r_obmat); + } + } + + return retval; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public Object Snapping API + * \{ */ + +SnapObjectContext *ED_transform_snap_object_context_create( + Main *bmain, Scene *scene, int flag) +{ + SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); + + sctx->flag = flag; + + sctx->bmain = bmain; + sctx->scene = scene; + + return sctx; +} + +SnapObjectContext *ED_transform_snap_object_context_create_view3d( + Main *bmain, Scene *scene, int flag, + /* extra args for view3d */ + ARegion *ar, View3D *v3d) +{ + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); + + sctx->use_v3d = true; + sctx->v3d_data.ar = ar; + sctx->v3d_data.v3d = v3d; + + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + sctx->cache.object_map = BLI_ghash_ptr_new(__func__); + sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + + return sctx; +} + +static void snap_object_data_free(void *val) +{ + SnapObjectData *sod = val; + for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { + if (sod->bvh_trees[i]) { + free_bvhtree_from_mesh(sod->bvh_trees[i]); + } + } +} + +void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) +{ + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free); + BLI_memarena_free(sctx->cache.mem_arena); + } + + MEM_freeN(sctx); +} + + +bool ED_transform_snap_object_project_ray_ex( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float r_no[3], int *r_index, + Object **r_ob, float r_obmat[4][4]) +{ + Base *base_act = params->use_object_active ? sctx->scene->basact : NULL; + Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL; + + return snapObjectsRay( + sctx, + params->snap_select, params->snap_to, + NULL, NULL, + base_act, obedit, + ray_start, ray_normal, ray_start, ray_depth, + r_loc, r_no, r_index, + r_ob, r_obmat); +} + +/** + * Convenience function for snap ray-casting. + * + * Given a ray, cast it into the scene (snapping to faces). + * + * \return Snap success + */ +static bool transform_snap_context_project_ray_impl( + SnapObjectContext *sctx, + const float ray_start[3], const float ray_normal[3], float *ray_dist, + float r_co[3], float r_no[3]) +{ + bool ret; + + /* try snap edge, then face if it fails */ + ret = ED_transform_snap_object_project_ray_ex( + sctx, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .snap_to = SCE_SNAP_MODE_FACE, + .use_object_edit = (sctx->scene->obedit != NULL), + }, + ray_start, ray_normal, ray_dist, + r_co, r_no, NULL, + NULL, NULL); + + return ret; +} + +bool ED_transform_snap_object_project_ray( + SnapObjectContext *sctx, + const float ray_origin[3], const float ray_direction[3], float *ray_dist, + float r_co[3], float r_no[3]) +{ + float ray_dist_fallback; + if (ray_dist == NULL) { + ray_dist_fallback = BVH_RAYCAST_DIST_MAX; + ray_dist = &ray_dist_fallback; + } + + float no_fallback[3]; + if (r_no == NULL) { + r_no = no_fallback; + } + + return transform_snap_context_project_ray_impl( + sctx, + ray_origin, ray_direction, ray_dist, + r_co, r_no); +} + +static bool transform_snap_context_project_view3d_mixed_impl( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + bool use_depth, + float r_co[3], float r_no[3]) +{ + float ray_dist = 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(params->snap_to_flag != 0); + BLI_assert((params->snap_to_flag & ~(1 | 2 | 4)) == 0); + + struct SnapObjectParams params_temp = *params; + + for (int i = 0; i < 3; i++) { + if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) { + if (use_depth == false) { + ray_dist = BVH_RAYCAST_DIST_MAX; + } + + params_temp.snap_to = elem_type[i]; + + if (ED_transform_snap_object_project_view3d( + sctx, + ¶ms_temp, + mval, dist_px, &ray_dist, + r_co, r_no)) + { + is_hit = true; + } + } + } + + return is_hit; +} + +/** + * Convenience function for performing snapping. + * + * Given a 2D region value, snap to vert/edge/face. + * + * \param sctx: Snap context. + * \param mval: Screenspace coordinate. + * \param dist_px: Maximum distance to snap (in pixels). + * \param use_depth: Snap to the closest element, use when using more than one snap type. + * \param r_co: hit location. + * \param r_no: hit normal (optional). + * \return Snap success + */ +bool ED_transform_snap_object_project_view3d_mixed( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval_fl[2], float *dist_px, + bool use_depth, + float r_co[3], float r_no[3]) +{ + return transform_snap_context_project_view3d_mixed_impl( + sctx, + params, + mval_fl, dist_px, use_depth, + r_co, r_no); +} + +bool ED_transform_snap_object_project_view3d_ex( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + float r_loc[3], float r_no[3], int *r_index) +{ + float ray_start[3], ray_normal[3], ray_orgigin[3]; + + if (!ED_view3d_win_to_ray_ex( + sctx->v3d_data.ar, sctx->v3d_data.v3d, + mval, ray_orgigin, ray_normal, ray_start, true)) + { + return false; + } + + Base *base_act = params->use_object_active ? sctx->scene->basact : NULL; + Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL; + return snapObjectsRay( + sctx, + params->snap_select, params->snap_to, + mval, dist_px, + base_act, obedit, + ray_start, ray_normal, ray_orgigin, ray_depth, + r_loc, r_no, r_index, NULL, NULL); +} + +bool ED_transform_snap_object_project_view3d( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + float r_loc[3], float r_no[3]) +{ + return ED_transform_snap_object_project_view3d_ex( + sctx, + params, + mval, dist_px, + ray_depth, + r_loc, r_no, NULL); +} + +/** \} */ diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index bc7a8374c73..441fd446cd6 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -40,7 +40,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 98efbb49ca7..2a58b1fd2ec 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -42,7 +42,7 @@ #include "BLT_translation.h" -#include "BKE_blender.h" +#include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" |