Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c20
-rw-r--r--source/blender/editors/curve/editcurve.c21
-rw-r--r--source/blender/editors/curve/editcurve_paint.c92
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c2
-rw-r--r--source/blender/editors/include/ED_transform.h87
-rw-r--r--source/blender/editors/include/ED_view3d.h12
-rw-r--r--source/blender/editors/interface/interface_handlers.c2
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_regions.c6
-rw-r--r--source/blender/editors/interface/interface_style.c6
-rw-r--r--source/blender/editors/interface/resources.c2
-rw-r--r--source/blender/editors/mask/mask_add.c89
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c11
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c28
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c10
-rw-r--r--source/blender/editors/mesh/editmesh_select.c47
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c26
-rw-r--r--source/blender/editors/object/object_bake.c6
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c3
-rw-r--r--source/blender/editors/render/render_internal.c3
-rw-r--r--source/blender/editors/screen/glutil.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/space_action/action_edit.c5
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c4
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c57
-rw-r--r--source/blender/editors/space_info/info_stats.c2
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_node/node_templates.c36
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c34
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h10
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c62
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c82
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c62
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c51
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.h10
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c899
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1207
-rw-r--r--source/blender/editors/util/editmode_undo.c2
-rw-r--r--source/blender/editors/util/undo.c2
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,
+ &params_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"