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/anim_draw.c90
-rw-r--r--source/blender/editors/animation/anim_filter.c2
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c8
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h4
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/interface/interface_layout.c28
-rw-r--r--source/blender/editors/interface/interface_widgets.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c444
-rw-r--r--source/blender/editors/object/object_relations.c6
-rw-r--r--source/blender/editors/object/object_vgroup.c61
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c27
-rw-r--r--source/blender/editors/transform/transform.h4
-rw-r--r--source/blender/editors/transform/transform_conversions.c7
-rw-r--r--source/blender/editors/transform/transform_snap.c10
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1632
21 files changed, 1278 insertions, 1081 deletions
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 33e44d73894..a4ba95420c1 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -46,6 +46,8 @@
#include "BLI_dlrbTree.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_mask.h"
@@ -308,7 +310,8 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
fcu->prev_norm_factor = 1.0f;
if (fcu->bezt) {
- BezTriple *bezt;
+ const bool use_preview_only = PRVRANGEON;
+ const BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
float min_coord = FLT_MAX;
@@ -318,28 +321,77 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return 1.0f;
}
- if (PRVRANGEON) {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
- max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
-
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
- min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
- }
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0],
+ scene->r.psfra,
+ scene->r.pefra))
+ {
+ continue;
}
- }
- else {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
+
+ if (i == 0) {
+ /* We ignore extrapolation flags and handle here, and use the
+ * control point position only. so we normalize "interesting"
+ * part of the curve.
+ *
+ * Here we handle left extrapolation.
+ */
max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ else {
+ const BezTriple *prev_bezt = bezt - 1;
+ if (prev_bezt->ipo == BEZT_IPO_CONST) {
+ /* Constant interpolation: previous CV value is used up
+ * to the current keyframe.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_LIN) {
+ /* Linear interpolation: min/max using both previous and
+ * and current CV.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_BEZ) {
+ const int resol = fcu->driver
+ ? 32
+ : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32);
+ if (resol < 2) {
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else {
+ float data[120];
+ float v1[2], v2[2], v3[2], v4[2];
+
+ v1[0] = prev_bezt->vec[1][0];
+ v1[1] = prev_bezt->vec[1][1];
+ v2[0] = prev_bezt->vec[2][0];
+ v2[1] = prev_bezt->vec[2][1];
+
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
+ BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
+
+ for (int j = 0; j <= resol; ++j) {
+ const float *fp = &data[j * 3];
+ max_coord = max_ff(max_coord, fp[1]);
+ min_coord = min_ff(min_coord, fp[1]);
+ }
+ }
+ }
}
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index c12a050e9ba..2f73eb6b71c 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -2223,7 +2223,7 @@ typedef struct tAnimFilterModifiersContext {
/* dependency walker callback for modifier dependencies */
-static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag))
+static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cb_flag))
{
tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
ID *owner_id = &ob->id;
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index cc4c1809fbc..f6c04e9570a 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -970,6 +970,9 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
ToolSettings *ts = CTX_data_tool_settings(C);
int point_added = 0;
+ /* TODO: Since the function `ED_transform_snap_object_context_create_view3d` creates a cache,
+ * the ideal would be to call this function only at the beginning of the snap operation,
+ * or at the beginning of the operator itself */
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));
@@ -1038,6 +1041,8 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
}
}
+ /* TODO: The ideal would be to call this function only once.
+ * At the end of the operator */
ED_transform_snap_object_context_destroy(snap_context);
return point_added;
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 5b011b679a6..e118e490f25 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -953,6 +953,9 @@ static int gp_dissolve_selected_points(bContext *C)
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
@@ -1165,6 +1168,9 @@ static int gp_delete_selected_points(bContext *C)
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
if (gps->flag & GP_STROKE_SELECT) {
@@ -1204,7 +1210,7 @@ static int gp_delete_exec(bContext *C, wmOperator *op)
case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
result = gp_delete_selected_points(C);
break;
-
+
case GP_DELETEOP_FRAME: /* active frame */
result = gp_actframe_delete_exec(C, op);
break;
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 7944b434057..6eaae49912c 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -65,10 +65,6 @@ struct SnapObjectParams {
unsigned int use_object_edit_cage : 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);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 8a2111fa6b2..b6d565e4e79 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -653,9 +653,9 @@ DEF_ICON(IPO_BACK)
DEF_ICON(IPO_EASE_IN)
DEF_ICON(IPO_EASE_OUT)
DEF_ICON(IPO_EASE_IN_OUT)
+DEF_ICON(NORMALIZE_FCURVES)
#ifndef DEF_ICON_BLANK_SKIP
/* available */
- DEF_ICON(BLANK203)
DEF_ICON(BLANK204)
DEF_ICON(BLANK205)
DEF_ICON(BLANK206)
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 7262b453e02..ca2538022b0 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2078,15 +2078,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- if (item->type == ITEM_BUTTON) {
- const uiBut *but = ((uiButtonItem *)item)->but;
- const bool icon_only = (but->flag & UI_HAS_ICON) && (but->str == NULL || but->str[0] == '\0');
-
- min_size_flag = min_size_flag && icon_only;
- }
- else {
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
- }
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
@@ -2232,15 +2224,7 @@ static void ui_litem_estimate_column(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- if (item->type == ITEM_BUTTON) {
- const uiBut *but = ((uiButtonItem *)item)->but;
- const bool icon_only = (but->flag & UI_HAS_ICON) && (but->str == NULL || but->str[0] == '\0');
-
- min_size_flag = min_size_flag && icon_only;
- }
- else {
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
- }
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
@@ -3336,6 +3320,14 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
bitem->item.type = ITEM_BUTTON;
bitem->but = but;
+
+ int w, h;
+ ui_item_size((uiItem *)bitem, &w, &h);
+ /* XXX uiBut hasn't scaled yet
+ * we can flag the button as not expandable, depending on its size */
+ if (w <= 2 * UI_UNIT_X)
+ bitem->item.flag |= UI_ITEM_MIN;
+
BLI_addtail(&layout->items, bitem);
if (layout->context) {
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d43a94c5514..b3736a71e74 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1584,7 +1584,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, false);
}
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index d2b2f12c1a5..fa2c1f25cfc 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -447,7 +447,8 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", -40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", ar->v2d.mask.ymin - ar->v2d.mask.ymax);
}
@@ -497,7 +498,8 @@ static int view_scrollup_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", 40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", BLI_rcti_size_y(&ar->v2d.mask));
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 8f004bcf72b..65ee097e8e1 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -306,7 +306,7 @@ 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,
+ CTX_data_main(C), CTX_data_scene(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b26989113d4..743efb246ab 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -75,26 +75,213 @@
/* join selected meshes into the active mesh, context sensitive
* return 0 if no join is made (error) and 1 if the join is done */
+static void join_mesh_single(
+ Main *bmain, Scene *scene,
+ Object *ob_dst, Base *base_src, float imat[4][4],
+ MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp,
+ CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata,
+ int totvert, int totedge, int totloop, int totpoly,
+ Key *key, Key *nkey,
+ Material **matar, int *matmap, int totcol,
+ int *vertofs, int *edgeofs, int *loopofs, int *polyofs)
+{
+ int a, b;
+
+ Mesh *me = base_src->object->data;
+ MVert *mvert = *mvert_pp;
+ MEdge *medge = *medge_pp;
+ MLoop *mloop = *mloop_pp;
+ MPoly *mpoly = *mpoly_pp;
+
+ if (me->totvert) {
+ /* merge customdata flag */
+ ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
+
+ /* standard data */
+ CustomData_merge(&me->vdata, vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+ CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
+
+ /* vertex groups */
+ MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
+
+ /* NB: vertex groups here are new version */
+ if (dvert) {
+ for (a = 0; a < me->totvert; a++) {
+ for (b = 0; b < dvert[a].totweight; b++) {
+ /* Find the old vertex group */
+ bDeformGroup *dg, *odg = BLI_findlink(&base_src->object->defbase, dvert[a].dw[b].def_nr);
+ int index;
+ if (odg) {
+ /* Search for a match in the new object, and set new index */
+ for (dg = ob_dst->defbase.first, index = 0; dg; dg = dg->next, index++) {
+ if (STREQ(dg->name, odg->name)) {
+ dvert[a].dw[b].def_nr = index;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* if this is the object we're merging into, no need to do anything */
+ if (base_src->object != ob_dst) {
+ float cmat[4][4];
+
+ /* watch this: switch matmul order really goes wrong */
+ mul_m4_m4m4(cmat, imat, base_src->object->obmat);
+
+ /* transform vertex coordinates into new space */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) {
+ mul_m4_v3(cmat, mvert->co);
+ }
+
+ /* for each shapekey in destination mesh:
+ * - if there's a matching one, copy it across (will need to transform vertices into new space...)
+ * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
+ */
+ if (key) {
+ /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this mesh has such a shapekey */
+ KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ mul_m4_v3(cmat, *cos);
+ }
+ }
+ else {
+ /* copy this mesh's vertex coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* for each shapekey in destination mesh:
+ * - if it was an 'original', copy the appropriate data from nkey
+ * - otherwise, copy across plain coordinates (no need to transform coordinates)
+ */
+ if (key) {
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this was one of the original shapekeys */
+ KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ }
+ }
+ else {
+ /* copy base-coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (me->totedge) {
+ CustomData_merge(&me->edata, edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+ CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
+
+ for (a = 0; a < me->totedge; a++, medge++) {
+ medge->v1 += *vertofs;
+ medge->v2 += *vertofs;
+ }
+ }
+
+ if (me->totloop) {
+ if (base_src->object != ob_dst) {
+ MultiresModifierData *mmd;
+
+ multiresModifier_prepare_join(scene, base_src->object, ob_dst);
+
+ if ((mmd = get_multires_modifier(scene, base_src->object, true))) {
+ ED_object_iter_other(bmain, base_src->object, true,
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
+ }
+ }
+
+ CustomData_merge(&me->ldata, ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
+
+ for (a = 0; a < me->totloop; a++, mloop++) {
+ mloop->v += *vertofs;
+ mloop->e += *edgeofs;
+ }
+ }
+
+ if (me->totpoly) {
+ if (matmap) {
+ /* make mapping for materials */
+ for (a = 1; a <= base_src->object->totcol; a++) {
+ Material *ma = give_current_material(base_src->object, a);
+
+ for (b = 0; b < totcol; b++) {
+ if (ma == matar[b]) {
+ matmap[a - 1] = b;
+ break;
+ }
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
+
+ for (a = 0; a < me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += *loopofs;
+ mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
+ }
+ }
+
+ /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
+ *vertofs += me->totvert;
+ *mvert_pp += me->totvert;
+ *edgeofs += me->totedge;
+ *medge_pp += me->totedge;
+ *loopofs += me->totloop;
+ *mloop_pp += me->totloop;
+ *polyofs += me->totpoly;
+ *mpoly_pp += me->totpoly;
+}
+
int join_mesh_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Material **matar, *ma;
+ Base *ob_base = CTX_data_active_base(C);
+ Object *ob = ob_base->object;
+ Material **matar = NULL, *ma;
Mesh *me;
- MVert *mvert, *mv;
+ MVert *mvert = NULL;
MEdge *medge = NULL;
MPoly *mpoly = NULL;
MLoop *mloop = NULL;
Key *key, *nkey = NULL;
- KeyBlock *kb, *okb, *kbn;
- float imat[4][4], cmat[4][4], *fp1, *fp2;
+ KeyBlock *kb, *kbn;
+ float imat[4][4];
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
- int i, j, index, haskey = 0, edgeofs, loopofs, polyofs;
+ int i, haskey = 0, edgeofs, loopofs, polyofs;
bool ok = false;
bDeformGroup *dg, *odg;
- MDeformVert *dvert;
CustomData vdata, edata, fdata, ldata, pdata;
if (scene->obedit) {
@@ -154,8 +341,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_mesh_tessface_clear(me);
/* new material indices and material array */
- matar = MEM_callocN(sizeof(void *) * totmat, "join_mesh matar");
- if (totmat) matmap = MEM_callocN(sizeof(int) * totmat, "join_mesh matmap");
+ if (totmat) {
+ matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar");
+ matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap");
+ }
totcol = ob->totcol;
/* obact materials in new main array, is nicer start! */
@@ -214,7 +403,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ma = give_current_material(base->object, a);
for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) break;
+ if (ma == matar[b]) {
+ break;
+ }
}
if (b == totcol) {
matar[b] = ma;
@@ -223,8 +414,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
totcol++;
}
- if (totcol >= MAXMAT)
+ if (totcol >= MAXMAT) {
break;
+ }
}
}
@@ -301,187 +493,41 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* inverse transform for all selected meshes in this object */
invert_m4_m4(imat, ob->obmat);
-
+
+ /* Add back active mesh first. This allows to keep things similar as they were, as much as possible (i.e. data from
+ * active mesh will remain first ones in new result of the merge, in same order for CD layers, etc. See also T50084.
+ */
+ join_mesh_single(
+ bmain, scene,
+ ob, ob_base, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
+
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
+ if (base->object == ob) {
+ continue;
+ }
/* only join if this is a mesh */
if (base->object->type == OB_MESH) {
- me = base->object->data;
-
- if (me->totvert) {
-
- /* merge customdata flag */
- ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
-
- /* standard data */
- CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
- CustomData_copy_data_named(&me->vdata, &vdata, 0, vertofs, me->totvert);
-
- /* vertex groups */
- dvert = CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
-
- /* NB: vertex groups here are new version */
- if (dvert) {
- for (i = 0; i < me->totvert; i++) {
- for (j = 0; j < dvert[i].totweight; j++) {
- /* Find the old vertex group */
- odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
- if (odg) {
- /* Search for a match in the new object, and set new index */
- for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) {
- if (STREQ(dg->name, odg->name)) {
- dvert[i].dw[j].def_nr = index;
- break;
- }
- }
- }
- }
- }
- }
-
- /* if this is the object we're merging into, no need to do anything */
- if (base->object != ob) {
- /* watch this: switch matmul order really goes wrong */
- mul_m4_m4m4(cmat, imat, base->object->obmat);
-
- /* transform vertex coordinates into new space */
- for (a = 0, mv = mvert; a < me->totvert; a++, mv++) {
- mul_m4_v3(cmat, mv->co);
- }
-
- /* for each shapekey in destination mesh:
- * - if there's a matching one, copy it across (will need to transform vertices into new space...)
- * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
- */
- if (key) {
- /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this mesh has such a shapekey */
- okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
-
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- mul_m4_v3(cmat, fp1);
- }
- }
- else {
- /* copy this mesh's vertex coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
- else {
- /* for each shapekey in destination mesh:
- * - if it was an 'original', copy the appropriate data from nkey
- * - otherwise, copy across plain coordinates (no need to transform coordinates)
- */
- if (key) {
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this was one of the original shapekeys */
- okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- }
- }
- else {
- /* copy base-coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
-
- /* advance mvert pointer to end of base mesh's data */
- mvert += me->totvert;
- }
-
- if (me->totedge) {
- CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
- CustomData_copy_data_named(&me->edata, &edata, 0, edgeofs, me->totedge);
-
- for (a = 0; a < me->totedge; a++, medge++) {
- medge->v1 += vertofs;
- medge->v2 += vertofs;
- }
- }
-
- if (me->totloop) {
- if (base->object != ob) {
- MultiresModifierData *mmd;
-
- multiresModifier_prepare_join(scene, base->object, ob);
+ join_mesh_single(
+ bmain, scene,
+ ob, base, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
- if ((mmd = get_multires_modifier(scene, base->object, true))) {
- ED_object_iter_other(bmain, base->object, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
- }
- }
-
- CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
- CustomData_copy_data_named(&me->ldata, &ldata, 0, loopofs, me->totloop);
-
- for (a = 0; a < me->totloop; a++, mloop++) {
- mloop->v += vertofs;
- mloop->e += edgeofs;
- }
- }
-
- if (me->totpoly) {
- if (totmat) {
- /* make mapping for materials */
- for (a = 1; a <= base->object->totcol; a++) {
- ma = give_current_material(base->object, a);
-
- for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) {
- matmap[a - 1] = b;
- break;
- }
- }
- }
- }
-
- CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
- CustomData_copy_data_named(&me->pdata, &pdata, 0, polyofs, me->totpoly);
-
- for (a = 0; a < me->totpoly; a++, mpoly++) {
- mpoly->loopstart += loopofs;
- mpoly->mat_nr = matmap ? matmap[(int)mpoly->mat_nr] : 0;
- }
-
- polyofs += me->totpoly;
- }
-
- /* these are used for relinking (cannot be set earlier,
- * or else reattaching goes wrong)
- */
- vertofs += me->totvert;
- edgeofs += me->totedge;
- loopofs += me->totloop;
-
/* free base, now that data is merged */
- if (base->object != ob)
+ if (base->object != ob) {
ED_base_object_free_and_unlink(bmain, scene, base);
+ }
}
}
CTX_DATA_END;
@@ -529,34 +575,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (totcol) {
me->mat = matar;
- ob->mat = MEM_callocN(sizeof(void *) * totcol, "join obmatar");
- ob->matbits = MEM_callocN(sizeof(char) * totcol, "join obmatbits");
+ ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
+ ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits");
+ MEM_freeN(matmap);
}
- else
- MEM_freeN(matar);
-
+
ob->totcol = me->totcol = totcol;
- if (matmap) MEM_freeN(matmap);
-
/* other mesh users */
test_all_objects_materials(bmain, (ID *)me);
/* free temp copy of destination shapekeys (if applicable) */
if (nkey) {
- /* XXX 2.5 Animato */
-#if 0
- /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
- if (nkey->ipo) {
- BKE_ipo_free(nkey->ipo);
- BLI_remlink(&bmain->ipo, nkey->ipo);
- MEM_freeN(nkey->ipo);
- }
-#endif
-
- BKE_key_free(nkey);
- BLI_remlink(&bmain->key, nkey);
- MEM_freeN(nkey);
+ /* We can assume nobody is using that ID currently. */
+ BKE_libblock_free_ex(bmain, nkey, false, false);
}
/* ensure newly inserted keys are time sorted */
@@ -564,7 +596,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
- DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag
+ DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d30022c01f8..b5fbe4ba586 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2133,7 +2133,7 @@ enum {
};
static int tag_localizable_looper(
- void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cd_flag))
+ void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cb_flag))
{
if (*id_pointer) {
(*id_pointer)->tag &= ~LIB_TAG_DOIT;
@@ -2170,12 +2170,12 @@ static void tag_localizable_objects(bContext *C, const int mode)
*/
for (Object *object = bmain->object.first; object; object = object->id.next) {
if ((object->id.tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
if (object->data) {
ID *data_id = (ID *) object->data;
if ((data_id->tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
}
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 56f59dca9a1..3c406764157 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -363,8 +363,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot
/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
- MDeformVert **dvert_array_from, **dvf;
- MDeformVert **dvert_array, **dv;
+ MDeformVert **dvert_array_from = NULL, **dvf;
+ MDeformVert **dvert_array = NULL, **dv;
int dvert_tot_from;
int dvert_tot;
int i;
@@ -375,26 +375,30 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
if (ob == ob_from)
return true;
- ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
-
- if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */
+ if (ob->data != ob_from->data) {
+ ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
- new_vgroup = true;
- }
- if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
+ new_vgroup = true;
+ }
- if (dvert_array) MEM_freeN(dvert_array);
- if (dvert_array_from) MEM_freeN(dvert_array_from);
+ if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if (dvert_array)
+ MEM_freeN(dvert_array);
+ if (dvert_array_from)
+ MEM_freeN(dvert_array_from);
- if (new_vgroup == true) {
- /* free the newly added vgroup since it wasn't compatible */
- BKE_object_defgroup_remove_all(ob);
- }
+ if (new_vgroup == true) {
+ /* free the newly added vgroup since it wasn't compatible */
+ BKE_object_defgroup_remove_all(ob);
+ }
- /* if true: both are 0 and nothing needs changing, consider this a success */
- return (dvert_tot == dvert_tot_from);
+ /* if true: both are 0 and nothing needs changing, consider this a success */
+ return (dvert_tot == dvert_tot_from);
+ }
}
/* do the copy */
@@ -412,22 +416,23 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
MEM_freeN(remap);
}
- dvf = dvert_array_from;
- dv = dvert_array;
+ if (dvert_array_from != NULL && dvert_array != NULL) {
+ dvf = dvert_array_from;
+ dv = dvert_array;
- for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
- if ((*dv)->dw)
- MEM_freeN((*dv)->dw);
+ for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
+ MEM_SAFE_FREE((*dv)->dw);
+ *(*dv) = *(*dvf);
- *(*dv) = *(*dvf);
+ if ((*dv)->dw) {
+ (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ }
+ }
- if ((*dv)->dw)
- (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ MEM_freeN(dvert_array);
+ MEM_freeN(dvert_array_from);
}
- MEM_freeN(dvert_array);
- MEM_freeN(dvert_array_from);
-
return true;
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 075b1faf502..964f4bcdd9c 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1256,21 +1256,6 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
}
break;
}
-
- /* removed since BKE_image_user_frame_calc is now called in view3d_draw_bgpic because screen_ops doesnt call the notifier. */
-#if 0
- if (wmn->category == NC_SCENE && wmn->data == ND_FRAME) {
- View3D *v3d = area->spacedata.first;
- BGpic *bgpic = v3d->bgpicbase.first;
-
- for (; bgpic; bgpic = bgpic->next) {
- if (bgpic->ima) {
- Scene *scene = wmn->reference;
- BKE_image_user_frame_calc(&bgpic->iuser, scene->r.cfra, 0);
- }
- }
- }
-#endif
}
const char *view3d_context_dir[] = {
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 688f459108b..aefe30bbe32 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -280,7 +280,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), CTX_data_scene(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 17c08ed4205..542dc410bc3 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -588,7 +588,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), walk->scene, SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), walk->scene, 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 31ffa019e4e..1916f9b4dab 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -3722,6 +3722,12 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
@@ -4339,9 +4345,22 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
{
TransData *td = t->data;
float tvec[3];
- int i;
- for (i = 0; i < t->total; i++, td++) {
+ /* The ideal would be "apply_snap_align_rotation" only when a snap point is found
+ * so, maybe inside this function is not the best place to apply this rotation.
+ * but you need "handle snapping rotation before doing the translation" (really?) */
+ const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
+ float pivot[3];
+ if (apply_snap_align_rotation) {
+ copy_v3_v3(pivot, t->tsnap.snapTarget);
+ /* The pivot has to be in local-space (see T49494) */
+ if (t->flag & (T_EDIT | T_POSE)) {
+ Object *ob = t->obedit ? t->obedit : t->poseobj;
+ mul_m4_v3(ob->imat, pivot);
+ }
+ }
+
+ for (int i = 0; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4352,7 +4371,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
bool use_rotate_offset = false;
/* handle snapping rotation before doing the translation */
- if (usingSnappingNormal(t)) {
+ if (apply_snap_align_rotation) {
float mat[3][3];
if (validSnappingNormal(t)) {
@@ -4370,7 +4389,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
unit_m3(mat);
}
- ElementRotation_ex(t, td, mat, t->tsnap.snapTarget);
+ ElementRotation_ex(t, td, mat, pivot);
if (td->loc) {
use_rotate_offset = true;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 7ea4448a44e..d60eb2f0778 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -84,8 +84,8 @@ typedef struct TransSnap {
bool peel;
bool snap_spatial_grid;
short status;
- float snapPoint[3]; /* snapping from this point */
- float snapTarget[3]; /* to this point */
+ float snapPoint[3]; /* snapping from this point (in global-space)*/
+ float snapTarget[3]; /* to this point (in global-space)*/
float snapNormal[3];
char snapNodeBorder;
ListBase points;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index ce3d903b8f6..091a5773cf0 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2393,7 +2393,12 @@ static void createTransEditVerts(TransInfo *t)
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ /* Only in case of rotation and resize, we want the elements of the edited
+ * object to behave as groups whose pivot are the individual origins
+ *
+ * TODO: use island_info to detect the closest point when the "Snap Target"
+ * in Blender UI is "Closest" */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode != TFM_TRANSLATION)) {
island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map);
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index f8bb124e943..318d2718969 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -569,7 +569,9 @@ static void initSnappingMode(TransInfo *t)
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(obedit == NULL) ) // Object Mode
{
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+ /* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
+ * TODO: perform self snap in gpencil_strokes */
+ t->tsnap.modeSelect = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_ALL : SNAP_NOT_SELECTED;
}
else {
/* Grid if snap is not possible */
@@ -599,7 +601,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ G.main, t->scene, 0,
t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
@@ -1214,7 +1216,7 @@ bool snapObjectsTransform(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
@@ -1304,7 +1306,7 @@ bool peelObjectsTransform(
t->tsnap.object_context,
mval,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
use_peel_object,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index fba965f69a7..7c9dc43dbe4 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -59,6 +59,24 @@
#include "transform.h"
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
+typedef struct SnapData {
+ short snap_to;
+ float mval[2];
+ float ray_origin[3];
+ float ray_start[3];
+ float ray_dir[3];
+ float pmat[4][4]; /* perspective matrix */
+ float win_half[2];/* win x and y */
+ enum eViewProj view_proj;
+ float depth_range[2];
+} SnapData;
+
typedef struct SnapObjectData {
enum {
SNAP_MESH = 1,
@@ -110,12 +128,6 @@ struct SnapObjectContext {
};
-enum eViewProj {
- VIEW_PROJ_NONE = -1,
- VIEW_PROJ_ORTHO = 0,
- VIEW_PROJ_PERSP = -1,
-};
-
static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
@@ -223,113 +235,87 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
/** \Common utilities
* \{ */
-
/**
- * Struct that kepts basic information about a BVHTree build from a editmesh.
+ * Generates a struct with the immutable parameters that will be used on all objects.
+ *
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * \param view_proj: ORTHO or PERSP.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \param mval: Mouse coords.
+ * (When NULL, ray-casting is handled without any projection matrix correction.)
+ * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
+ * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
+ * \param ray_direction: Unit length direction of the ray.
+ * \param depth_range: distances of clipe plane min and clip plane max;
*/
-typedef struct BVHTreeFromMeshType {
- void *userdata;
- char type;
-} BVHTreeFromMeshType;
-
-typedef struct PreDefProject {
- float pmat[4][4]; /* perspective matrix multiplied by object matrix */
- float win_half[2];
- float dist_px_sq;
-} PreDefProject;
+static void snap_data_set(
+ SnapData *snapdata,
+ const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj,
+ const float mval[2], const float ray_origin[3], const float ray_start[3],
+ const float ray_direction[3], const float depth_range[2])
+{
+ if (ar) {
+ copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat);
+ snapdata->win_half[0] = ar->winx / 2;
+ snapdata->win_half[1] = ar->winy / 2;
+ }
+ if (mval) {
+ copy_v2_v2(snapdata->mval, mval);
+ }
+ snapdata->snap_to = snap_to;
+ copy_v3_v3(snapdata->ray_origin, ray_origin);
+ copy_v3_v3(snapdata->ray_start, ray_start);
+ copy_v3_v3(snapdata->ray_dir, ray_direction);
+ snapdata->view_proj = view_proj;
+ copy_v2_v2(snapdata->depth_range, depth_range);
+}
-static void precalc_project(
- PreDefProject *projectdefs, const ARegion *ar,
- const float dist_px, float obmat[4][4])
+MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
{
- float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat;
- if (obmat) {
- mul_m4_m4m4(projectdefs->pmat, pmat, obmat);
- }
- else {
- copy_m4_m4(projectdefs->pmat, pmat);
- }
- projectdefs->win_half[0] = ar->winx / 2;
- projectdefs->win_half[1] = ar->winy / 2;
- projectdefs->dist_px_sq = SQUARE(dist_px);
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_start);
+ return dot_v3v3(dvec, ray_dir);
}
-static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
+static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data)
{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert;
- return vert[index].co;
- }
- case SNAP_EDIT_MESH:
- {
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- return eve->co;
- }
- }
- return NULL;
+ const MVert *vert = data->vert + index;
+
+ normal_short_to_float_v3(r_no, vert->no);
}
-static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
+static void copy_bvert_no(const int index, float r_no[3], const BVHTreeFromEditMesh *data)
{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert + index;
- normal_short_to_float_v3(r_no, vert->no);
- break;
- }
- case SNAP_EDIT_MESH:
- {
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- copy_v3_v3(r_no, eve->no);
- break;
- }
- }
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+
+ copy_v3_v3(r_no, eve->no);
}
-static void get_edge_verts(
- const BVHTreeFromMeshType *meshdata, const int index,
- const float *v_pair[2])
+static void get_dm_edge_verts(const int index, const float *v_pair[2], const BVHTreeFromMesh *data)
{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
+ v_pair[0] = vert[edge->v1].co;
+ v_pair[1] = vert[edge->v2].co;
+}
- v_pair[0] = vert[edge->v1].co;
- v_pair[1] = vert[edge->v2].co;
- break;
- }
- case SNAP_EDIT_MESH:
- {
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+static void get_bedge_verts(const int index, const float *v_pair[2], const BVHTreeFromEditMesh *data)
+{
+ BMEdge *eed = BM_edge_at_index(data->em->bm, index);
- v_pair[0] = eed->v1->co;
- v_pair[1] = eed->v2->co;
- break;
- }
- }
+ v_pair[0] = eed->v1->co;
+ v_pair[1] = eed->v2->co;
}
static bool test_projected_vert_dist(
- PreDefProject *projectdefs,
- const float co[3], const enum eViewProj view_proj,
- const float mval[2], const float depth_range[2],
- float r_co[3])
+ const float depth_range[2], const float mval[2], const float co[3],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ float *dist_px_sq, float r_co[3])
{
float depth;
- float(*pmat)[4] = projectdefs->pmat;
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
depth = mul_project_m4_v3_zfac(pmat, co);
if (depth < depth_range[0] || depth > depth_range[1]) {
return false;
@@ -341,109 +327,106 @@ static bool test_projected_vert_dist(
(dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
};
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
mul_v2_fl(co2d, 1 / depth);
}
co2d[0] += 1.0f;
co2d[1] += 1.0f;
- co2d[0] *= projectdefs->win_half[0];
- co2d[1] *= projectdefs->win_half[1];
+ co2d[0] *= win_half[0];
+ co2d[1] *= win_half[1];
const float dist_sq = len_squared_v2v2(mval, co2d);
- if (dist_sq < projectdefs->dist_px_sq) {
+ if (dist_sq < *dist_px_sq) {
copy_v3_v3(r_co, co);
- projectdefs->dist_px_sq = dist_sq;
+ *dist_px_sq = dist_sq;
return true;
}
return false;
}
static bool test_projected_edge_dist(
- PreDefProject *projectdefs,
- const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3],
- const enum eViewProj view_proj, const float mval[2], const float depth_range[2],
- float r_co[3])
+ const float depth_range[2], const float mval[2],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ const float ray_start[3], const float ray_dir[3],
+ const float va[3], const float vb[3],
+ float *dist_px_sq, float r_co[3])
{
float tmp_co[3], depth;
- dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth);
- return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co);
+ dist_squared_ray_to_seg_v3(ray_start, ray_dir, va, vb, tmp_co, &depth);
+ return test_projected_vert_dist(depth_range, mval, tmp_co, pmat, win_half, is_persp, dist_px_sq, r_co);
}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \Walk DFS
- * \{ */
-typedef struct Object_Nearest2dPrecalc {
+typedef struct Nearest2dPrecalc {
float ray_origin_local[3];
float ray_direction_local[3];
float ray_inv_dir[3];
- PreDefProject projectdefs;
+ float ray_min_dist;
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ bool is_persp;
+ float win_half[2];
+
float mval[2];
bool sign[3];
- bool r_axis_closest[3];
- float depth_range[2];
-
- void *userdata;
- int index;
- float co[3];
- float no[3];
-} Object_Nearest2dPrecalc;
+} Nearest2dPrecalc;
-
-static void nearest2d_precalc(
- Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar,
- const float dist_px, float obmat[4][4],
- const float ray_origin_local[3], const float ray_direction_local[3],
- const float mval[2], const float depth_range[2])
+/**
+ * \param lpmat: Perspective matrix multiplied by object matrix
+ */
+static void dist_squared_to_projected_aabb_precalc(
+ struct Nearest2dPrecalc *neasrest_precalc,
+ float lpmat[4][4], bool is_persp, const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3])
{
- precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ copy_m4_m4(neasrest_precalc->pmat, lpmat);
+ neasrest_precalc->is_persp = is_persp;
+ copy_v2_v2(neasrest_precalc->win_half, win_half);
+ neasrest_precalc->ray_min_dist = ray_min_dist;
+
copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local);
copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local);
copy_v2_v2(neasrest_precalc->mval, mval);
- copy_v2_v2(neasrest_precalc->depth_range, depth_range);
for (int i = 0; i < 3; i++) {
- neasrest_precalc->ray_inv_dir[i] =
+ neasrest_precalc->ray_inv_dir[i] =
(neasrest_precalc->ray_direction_local[i] != 0.0f) ?
(1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX;
neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
- neasrest_precalc->r_axis_closest[i] = true;
}
}
-static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
+static float dist_squared_to_projected_aabb(
+ struct Nearest2dPrecalc *data,
+ const float bbmin[3], const float bbmax[3],
+ bool r_axis_closest[3])
{
- Object_Nearest2dPrecalc *data = user_data;
float local_bvmin[3], local_bvmax[3];
if (data->sign[0]) {
- local_bvmin[0] = bounds[0].max;
- local_bvmax[0] = bounds[0].min;
+ local_bvmin[0] = bbmax[0];
+ local_bvmax[0] = bbmin[0];
}
else {
- local_bvmin[0] = bounds[0].min;
- local_bvmax[0] = bounds[0].max;
+ local_bvmin[0] = bbmin[0];
+ local_bvmax[0] = bbmax[0];
}
if (data->sign[1]) {
- local_bvmin[1] = bounds[1].max;
- local_bvmax[1] = bounds[1].min;
+ local_bvmin[1] = bbmax[1];
+ local_bvmax[1] = bbmin[1];
}
else {
- local_bvmin[1] = bounds[1].min;
- local_bvmax[1] = bounds[1].max;
+ local_bvmin[1] = bbmin[1];
+ local_bvmax[1] = bbmax[1];
}
if (data->sign[2]) {
- local_bvmin[2] = bounds[2].max;
- local_bvmax[2] = bounds[2].min;
+ local_bvmin[2] = bbmax[2];
+ local_bvmax[2] = bbmin[2];
}
else {
- local_bvmin[2] = bounds[2].min;
- local_bvmax[2] = bounds[2].max;
+ local_bvmin[2] = bbmin[2];
+ local_bvmax[2] = bbmax[2];
}
const float tmin[3] = {
@@ -456,9 +439,9 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
(local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
(local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
};
- /* va[3] and vb[3] are the coordinates of the AABB edge closest to the ray */
+ /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
float va[3], vb[3];
- /* rtmin and rtmax are the distances of the minimum and maximum ray hits on the AABB */
+ /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
float rtmin, rtmax;
int main_axis;
@@ -466,38 +449,38 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
rtmax = tmax[0];
va[0] = vb[0] = local_bvmax[0];
main_axis = 3;
- data->r_axis_closest[0] = data->sign[0];
+ r_axis_closest[0] = data->sign[0];
}
else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
rtmax = tmax[1];
va[1] = vb[1] = local_bvmax[1];
main_axis = 2;
- data->r_axis_closest[1] = data->sign[1];
+ r_axis_closest[1] = data->sign[1];
}
else {
rtmax = tmax[2];
va[2] = vb[2] = local_bvmax[2];
main_axis = 1;
- data->r_axis_closest[2] = data->sign[2];
+ r_axis_closest[2] = data->sign[2];
}
if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
rtmin = tmin[0];
va[0] = vb[0] = local_bvmin[0];
main_axis -= 3;
- data->r_axis_closest[0] = !data->sign[0];
+ r_axis_closest[0] = !data->sign[0];
}
else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
rtmin = tmin[1];
va[1] = vb[1] = local_bvmin[1];
main_axis -= 1;
- data->r_axis_closest[1] = !data->sign[1];
+ r_axis_closest[1] = !data->sign[1];
}
else {
rtmin = tmin[2];
va[2] = vb[2] = local_bvmin[2];
main_axis -= 2;
- data->r_axis_closest[2] = !data->sign[2];
+ r_axis_closest[2] = !data->sign[2];
}
if (main_axis < 0) {
main_axis += 3;
@@ -505,25 +488,34 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
/* if rtmin < rtmax, ray intersect `AABB` */
if (rtmin <= rtmax) {
+#define IGNORE_BEHIND_RAY
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmax < depth_min`, the hit is behind us
- * TODO: Check if the entire AABB is behind ray
- * this will prevent unnecessary leaf testing*/
- if (rtmax < depth_range[0]) {
- return false;
+ /* `if rtmax < depth_min`, the hit is behind us */
+ if (rtmax < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#endif
const float proj = rtmin * data->ray_direction_local[main_axis];
- data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
- return true;
+ r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
+ return 0.0f;
}
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmin < depth_min`, the hit is behing us
- * TODO: Check if the entire AABB is behind ray */
- else if (rtmin < depth_range[0]) {
- return false;
+ /* `if rtmin < depth_min`, the hit is behing us */
+ else if (rtmin < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#endif
+#undef IGNORE_BEHIND_RAY
if (data->sign[main_axis]) {
va[main_axis] = local_bvmax[main_axis];
vb[main_axis] = local_bvmin[main_axis];
@@ -534,31 +526,35 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
}
float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
- float (*pmat)[4] = data->projectdefs.pmat;
- float depth_a = mul_project_m4_v3_zfac(pmat, va);
- float depth_b = depth_a + pmat[main_axis][3] * scale;
+ float (*pmat)[4] = data->pmat;
float va2d[2] = {
(dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
(dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
};
float vb2d[2] = {
- (va2d[0] + pmat[main_axis][0] * scale) / depth_b,
- (va2d[1] + pmat[main_axis][1] * scale) / depth_b,
+ (va2d[0] + pmat[main_axis][0] * scale),
+ (va2d[1] + pmat[main_axis][1] * scale),
};
- va2d[0] /= depth_a;
- va2d[1] /= depth_a;
+ if (data->is_persp) {
+ float depth_a = mul_project_m4_v3_zfac(pmat, va);
+ float depth_b = depth_a + pmat[main_axis][3] * scale;
+ va2d[0] /= depth_a;
+ va2d[1] /= depth_a;
+ vb2d[0] /= depth_b;
+ vb2d[1] /= depth_b;
+ }
va2d[0] += 1.0f;
va2d[1] += 1.0f;
vb2d[0] += 1.0f;
vb2d[1] += 1.0f;
- va2d[0] *= data->projectdefs.win_half[0];
- va2d[1] *= data->projectdefs.win_half[1];
- vb2d[0] *= data->projectdefs.win_half[0];
- vb2d[1] *= data->projectdefs.win_half[1];
+ va2d[0] *= data->win_half[0];
+ va2d[1] *= data->win_half[1];
+ vb2d[0] *= data->win_half[0];
+ vb2d[1] *= data->win_half[1];
//float dvec[2], edge[2], rdist;
//sub_v2_v2v2(dvec, data->mval, va2d);
@@ -571,73 +567,146 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
lambda /= edge[0] * edge[0] + edge[1] * edge[1];
if (lambda <= 0.0f) {
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = true;
+ r_axis_closest[main_axis] = true;
}
else if (lambda >= 1.0f) {
rdist = len_squared_v2v2(data->mval, vb2d);
- data->r_axis_closest[main_axis] = false;
+ r_axis_closest[main_axis] = false;
}
else {
va2d[0] += edge[0] * lambda;
va2d[1] += edge[1] * lambda;
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = lambda < 0.5f;
+ r_axis_closest[main_axis] = lambda < 0.5f;
}
}
else {
rdist = len_squared_v2v2(data->mval, va2d);
}
- return rdist < data->projectdefs.dist_px_sq;
+ return rdist;
+}
+
+static float dist_squared_to_projected_aabb_simple(
+ float lpmat[4][4], const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3],
+ const float bbmin[3], const float bbmax[3])
+{
+ struct Nearest2dPrecalc data;
+ dist_squared_to_projected_aabb_precalc(
+ &data, lpmat, true, win_half, ray_min_dist,
+ mval, ray_origin_local, ray_direction_local);
+
+ bool dummy[3] = {true, true, true};
+ return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
+}
+
+static float dist_aabb_to_plane(
+ const float bbmin[3], const float bbmax[3],
+ const float plane_co[3], const float plane_no[3])
+{
+ const float local_bvmin[3] = {
+ (plane_no[0] < 0) ? bbmax[0] : bbmin[0],
+ (plane_no[1] < 0) ? bbmax[1] : bbmin[1],
+ (plane_no[2] < 0) ? bbmax[2] : bbmin[2],
+ };
+ return depth_get(local_bvmin, plane_co, plane_no);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \Walk DFS
+ * \{ */
+
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const float *v_pair[2], void *data);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
+
+typedef struct Nearest2dUserData {
+ struct Nearest2dPrecalc data_precalc;
+
+ float dist_px_sq;
+
+ bool r_axis_closest[3];
+
+ float depth_range[2];
+
+ void *userdata;
+ Nearest2DGetEdgeVertsCallback get_edge_verts;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ int index;
+ float co[3];
+ float no[3];
+} Nearest2dUserData;
+
+
+static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+{
+ Nearest2dUserData *data = user_data;
+ const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
+ const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
+ const float rdist = dist_squared_to_projected_aabb(
+ &data->data_precalc, bbmin, bbmax, data->r_axis_closest);
+ return rdist < data->dist_px_sq;
}
static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float co[3] = {
(bounds[0].min + bounds[0].max) / 2,
(bounds[1].min + bounds[1].max) / 2,
(bounds[2].min + bounds[2].max) / 2,
};
- /* Although this function is also used in the Othogonal view (VIEW_PROJ_ORTHO),
- * we put `eViewProj view_proj` as` VIEW_PROJ_PERSP` because it works in both cases
- * (with the disadvantage of executing unnecessary calculations) */
if (test_projected_vert_dist(
- &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP,
- neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ data->depth_range,
+ neasrest_precalc->mval, co,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ &data->dist_px_sq,
+ data->co))
{
- copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
- neasrest_precalc->index = index;
+ data->copy_vert_no(index, data->no, data->userdata);
+ data->index = index;
}
return true;
}
static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float *v_pair[2];
- get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+ data->get_edge_verts(index, v_pair, data->userdata);
- /* Although this function is also used in the Othogonal view (VIEW_PROJ_ORTHO),
- * we put `eViewProj view_proj` as` VIEW_PROJ_PERSP` because it works in both cases
- * (with the disadvantage of executing unnecessary calculations) */
if (test_projected_edge_dist(
- &neasrest_precalc->projectdefs, v_pair[0], v_pair[1],
- neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local,
- VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ data->depth_range,
+ neasrest_precalc->mval,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ neasrest_precalc->ray_origin_local,
+ neasrest_precalc->ray_direction_local,
+ v_pair[0], v_pair[1],
+ &data->dist_px_sq,
+ data->co))
{
- sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
- neasrest_precalc->index = index;
+ sub_v3_v3v3(data->no, v_pair[0], v_pair[1]);
+ data->index = index;
}
return true;
}
static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
{
- const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest;
+ const bool *r_axis_closest = ((struct Nearest2dUserData *)userdata)->r_axis_closest;
return r_axis_closest[axis];
}
@@ -649,46 +718,56 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
* \{ */
static bool snapArmature(
- const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const short snap_to, const float origin[3], const float dir[3],
- const float mval[2], const enum eViewProj view_proj, const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, bArmature *arm, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
- float ray_start_local[3], ray_normal_local[3];
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ float ray_start_local[3], ray_normal_local[3]; /* Used only in the snap to edges */
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, origin);
- copy_v3_v3(ray_normal_local, dir);
+ copy_v3_v3(ray_start_local, snapdata->ray_origin);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
mul_m4_v3(imat, ray_start_local);
mul_mat3_m4_v3(imat, ray_normal_local);
}
+ else if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) { /* Currently only edge and vert */
+ return retval;
+ }
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
if (arm->edbo) {
for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->head,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->tail,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ eBone->head, eBone->tail,
+ &dist_px_sq, r_loc);
break;
}
}
@@ -703,52 +782,60 @@ static bool snapArmature(
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, head_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, tail_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ head_vec, tail_vec,
+ &dist_px_sq, r_loc);
break;
}
}
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
}
static bool snapCurve(
- const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, Curve *cu, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
if (ob->mode == OB_MODE_EDIT) {
@@ -758,19 +845,25 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) &&
!(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
{
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[0],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[2],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -779,7 +872,9 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -787,11 +882,15 @@ static bool snapCurve(
if (nu->pntsu > 1) {
if (nu->bezt) {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
else {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
}
@@ -803,8 +902,9 @@ static bool snapCurve(
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -812,11 +912,10 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- const ARegion *ar, Object *ob, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
@@ -827,15 +926,19 @@ static bool snapEmpty(
}
/* for now only vertex supported */
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, NULL);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
float tmp_co[3];
copy_v3_v3(tmp_co, obmat[3]);
- if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ if (test_projected_vert_dist(
+ snapdata->depth_range, snapdata->mval, tmp_co,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc)) {
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
retval = true;
}
break;
@@ -848,18 +951,17 @@ static bool snapEmpty(
}
static bool snapCamera(
- const SnapObjectContext *sctx, Object *object, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ const SnapObjectContext *sctx, SnapData *snapdata,
+ Object *object, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
Scene *scene = sctx->scene;
- PreDefProject projectdefs;
- precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
@@ -880,7 +982,7 @@ static bool snapCamera(
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
MovieTrackingObject *tracking_object;
@@ -920,7 +1022,9 @@ static bool snapCamera(
mul_m4_v3(vertex_obmat, bundle_pos);
retval |= test_projected_vert_dist(
- &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, bundle_pos,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
@@ -931,7 +1035,8 @@ static bool snapCamera(
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -943,18 +1048,10 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-struct NearestDM_Data {
- void *bvhdata;
- const float *depth_range;
- float *ray_depth;
-};
-
static bool snapDerivedMesh(
- SnapObjectContext *sctx,
+ SnapObjectContext *sctx, SnapData *snapdata,
Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ bool do_bb,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -963,12 +1060,12 @@ static bool snapDerivedMesh(
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
if (dm->getNumPolys(dm) == 0) {
return retval;
}
}
- else if (snap_to == SCE_SNAP_MODE_EDGE) {
+ else if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -979,251 +1076,259 @@ static bool snapDerivedMesh(
}
}
- {
- bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
+ bool need_ray_start_correction_init =
+ (snapdata->snap_to == SCE_SNAP_MODE_FACE) &&
+ (snapdata->view_proj == VIEW_PROJ_ORTHO);
- 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;
+ 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);
+ 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);
+ copy_v3_v3(ray_start_local, snapdata->ray_start);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ 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;
- }
+ /* 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);
+ float lpmat[4][4];
+ float ray_org_local[3];
+ float ray_min_dist;
+ if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ ray_min_dist = snapdata->depth_range[0] * local_scale;
+ }
- if (bb) {
- BoundBox bb_temp;
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
- /* We cannot afford a bounding box 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);
+ if (do_bb) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
- /* 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;
- }
+ if (bb) {
+ BoundBox bb_temp;
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
+ /* We cannot afford a bounding box 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);
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
+ /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see T46816. */
+ if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ float dist_px_sq = dist_squared_to_projected_aabb_simple(
+ lpmat, snapdata->win_half, ray_min_dist, snapdata->mval,
+ ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]);
+ if (dist_px_sq > SQUARE(*dist_px))
+ {
return retval;
}
- need_ray_start_correction_init = false;
- }
- }
-
- SnapObjectData_Mesh *sod = NULL;
- BVHTreeFromMesh *treedata = NULL, treedata_stack;
-
- 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_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
- }
-
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- case SCE_SNAP_MODE_EDGE:
- 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_calloc(sctx->cache.mem_arena, sizeof(*treedata));
- }
- treedata = sod->bvh_trees[tree_index];
-
- /* the tree is owned by the DM and may have been freed since we last used! */
- if (treedata && treedata->tree) {
- if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!isect_ray_aabb_v3_simple(
+ ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL))
+ {
+ return retval;
}
}
+ /* was local_depth, see: T47838 */
+ len_diff = dist_aabb_to_plane(bb->vec[0], bb->vec[6], ray_start_local, ray_normal_local);
+ if (len_diff < 0) len_diff = 0.0f;
+ need_ray_start_correction_init = false;
}
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
+ }
+
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata = NULL;
+
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ 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_calloc(sctx->cache.mem_arena, sizeof(*treedata));
}
+ treedata = sod->bvh_trees[tree_index];
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
- break;
- case SCE_SNAP_MODE_EDGE:
- bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
- break;
- case SCE_SNAP_MODE_VERTEX:
- bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
- break;
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata && treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
}
}
+ }
- if (!treedata || !treedata->tree) {
- return retval;
+ if (treedata && treedata->tree == NULL) {
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
+ break;
}
+ }
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
- }
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ if (need_ray_start_correction_init) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
}
- float ray_org_local[3];
-
- 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.
+ }
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
+ /* 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. */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
madd_v3_v3v3fl(
- ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
+ ray_start_local, ray_org_local, ray_normal_local,
+ len_diff + snapdata->depth_range[0] * local_scale);
local_depth -= len_diff;
}
- else {
- len_diff = 0.0f;
- }
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (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);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- 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]);
- }
- }
- }
- }
+ else len_diff = 0.0f;
}
- /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */
else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH};
-
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
-
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
+ len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+ if (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);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
+ retval = true;
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ }
}
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
}
}
-
- if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_mesh(treedata);
+ }
+ /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */
+ else {
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
+ .userdata = treedata,
+ .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no,
+ .index = -1};
+
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
+
+ retval = true;
}
}
@@ -1231,11 +1336,8 @@ static bool snapDerivedMesh(
}
static bool snapEditMesh(
- SnapObjectContext *sctx,
+ SnapObjectContext *sctx, SnapData *snapdata,
Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1244,12 +1346,12 @@ static bool snapEditMesh(
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
if (em->bm->totface == 0) {
return retval;
}
}
- if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
return retval;
}
@@ -1260,254 +1362,246 @@ static bool snapEditMesh(
}
}
- {
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3];
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3];
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_normal_local, ray_normal);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
- SnapObjectData_EditMesh *sod = NULL;
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
+ float local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
- BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
+ SnapObjectData_EditMesh *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_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_EDIT_MESH;
- }
+ BVHTreeFromEditMesh *treedata = NULL;
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- case SCE_SNAP_MODE_EDGE:
- 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_calloc(sctx->cache.mem_arena, sizeof(*treedata));
- }
- treedata = sod->bvh_trees[tree_index];
- }
- }
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ 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_calloc(sctx->cache.mem_arena, sizeof(*treedata));
}
+ treedata = sod->bvh_trees[tree_index];
+ }
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- BLI_bitmap *looptri_mask = NULL;
- int looptri_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- em->bm, looptri_mask,
- sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
- if (looptri_mask) {
- MEM_freeN(looptri_mask);
- }
- break;
+ if (treedata && treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ int looptri_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ em->bm, elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
}
- case SCE_SNAP_MODE_EDGE:
- {
- BLI_bitmap *edges_mask = NULL;
- int edges_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_edge_fn) {
- edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
- edges_num_active = BM_iter_mesh_bitmap_from_filter(
- BM_EDGES_OF_MESH, em->bm, edges_mask,
- (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
- sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
- if (edges_mask) {
- MEM_freeN(edges_mask);
- }
- break;
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL);
+ break;
+ }
+ case SCE_SNAP_MODE_EDGE:
+ {
+ int edges_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_edge_fn) {
+ elem_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
+ edges_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_EDGES_OF_MESH, em->bm, elem_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
+ sctx->callbacks.edit_mesh.user_data);
}
- case SCE_SNAP_MODE_VERTEX:
- {
- BLI_bitmap *verts_mask = NULL;
- int verts_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_vert_fn) {
- verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
- verts_num_active = BM_iter_mesh_bitmap_from_filter(
- BM_VERTS_OF_MESH, em->bm, verts_mask,
- (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
- sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
- if (verts_mask) {
- MEM_freeN(verts_mask);
- }
- break;
+ bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6);
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ int verts_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_vert_fn) {
+ elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ verts_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_VERTS_OF_MESH, em->bm, elem_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
+ sctx->callbacks.edit_mesh.user_data);
}
+ bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6);
+ break;
}
}
-
- if (!treedata || !treedata->tree) {
- return retval;
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
}
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- float ray_start_local[3];
- copy_v3_v3(ray_start_local, ray_start);
- mul_m4_v3(imat, ray_start_local);
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
- /* local scale in normal direction */
- float local_scale = normalize_v3(ray_normal_local);
- float local_depth = *ray_depth;
- if (local_depth != BVH_RAYCAST_DIST_MAX) {
- local_depth *= local_scale;
- }
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
+ float ray_start_local[3];
+ copy_v3_v3(ray_start_local, snapdata->ray_start);
+ mul_m4_v3(imat, ray_start_local);
- /* 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!
+ /* 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!
+ */
+ float len_diff = 0.0f;
+ if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
*/
- float len_diff = 0.0f;
- if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- if (BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
- {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
+ {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
+ copy_v3_v3(ray_org_local, snapdata->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. */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
madd_v3_v3v3fl(
- ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
+ ray_start_local, ray_org_local, ray_normal_local,
+ len_diff + snapdata->depth_range[0] * local_scale);
local_depth -= len_diff;
}
+ else len_diff = 0.0f;
}
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (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);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- retval = true;
-
- if (r_index) {
- *r_index = hit.index;
- }
- }
- }
- }
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
}
else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH};
-
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
-
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+ if (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);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
+ retval = true;
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+ if (r_index) {
+ *r_index = hit.index;
+ }
}
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
}
}
-
- if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_editmesh(treedata);
+ }
+ else {
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
+ .userdata = treedata,
+ .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no,
+ .index = -1};
+
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ (snapdata->depth_range[0] * local_scale), snapdata->mval,
+ ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
+
+ retval = true;
}
}
@@ -1520,11 +1614,9 @@ static bool snapEditMesh(
* \note Duplicate args here are documented at #snapObjectsRay
*/
static bool snapObject(
- SnapObjectContext *sctx,
+ SnapObjectContext *sctx, SnapData *snapdata,
Object *ob, float obmat[4][4], const unsigned int ob_index,
- bool use_obedit, const short snap_to, const float mval[2],
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ bool use_obedit,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1532,12 +1624,6 @@ static bool snapObject(
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- const enum eViewProj view_proj =
- ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE :
- (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO);
-
- const ARegion *ar = sctx->v3d_data.ar;
-
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1546,9 +1632,7 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, ob_index,
- snap_to, mval, view_proj,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, em, obmat, ob_index,
ray_depth, dist_px,
r_loc, r_no, r_index,
r_hit_list);
@@ -1565,9 +1649,8 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, ob_index,
- snap_to, mval, view_proj, true,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, dm, obmat, ob_index,
+ true,
ray_depth, dist_px,
r_loc, r_no,
r_index, r_hit_list);
@@ -1575,32 +1658,32 @@ static bool snapObject(
dm->release(dm);
}
}
- else if (snap_to != SCE_SNAP_MODE_FACE) {
+ else if (snapdata->snap_to != SCE_SNAP_MODE_FACE) {
if (ob->type == OB_ARMATURE) {
retval = snapArmature(
- ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal,
- mval, view_proj, depth_range, dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CURVE) {
retval = snapCurve(
- ar, ob, ob->data, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_EMPTY) {
retval = snapEmpty(
- ar, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CAMERA) {
retval = snapCamera(
- sctx, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ sctx, snapdata, ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
}
@@ -1622,18 +1705,9 @@ static bool snapObject(
* Walks through all objects in the scene to find the closest snap element ray.
*
* \param sctx: Snap context to store data.
- * \param snap_to: Element to snap, Vertice, Edge or Face.
- * Currently only works one at a time, but can eventually operate as flag.
- *
+ * \param snapdata: struct generated in `get_snapdata`.
* \param snap_select: from enum SnapSelect.
- *
* \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
- * \param mval: Mouse coords.
- * When NULL, ray-casting is handled without any projection matrix correction.
- * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
- * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
- * \param ray_normal: Unit length direction of the ray.
- * \param depth_range: distances of clipe plane min and clip plane max;
*
* Read/Write Args
* ---------------
@@ -1654,11 +1728,9 @@ static bool snapObject(
*
*/
static bool snapObjectsRay(
- SnapObjectContext *sctx,
- const unsigned short snap_to, const SnapSelect snap_select,
- const bool use_object_edit_cage, const float mval[2],
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ const SnapSelect snap_select,
+ const bool use_object_edit_cage,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1681,9 +1753,7 @@ static bool snapObjectsRay(
Object *ob = base_act->object;
retval |= snapObject(
- sctx, ob, ob->obmat, ob_index++,
- false, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, ob->obmat, ob_index++, false,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1717,9 +1787,8 @@ static bool snapObjectsRay(
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, ob_index++,
- use_obedit_dupli, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, dupli_snap, dupli_ob->mat,
+ ob_index++, use_obedit_dupli,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1731,9 +1800,7 @@ static bool snapObjectsRay(
Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
- sctx, ob_snap, ob->obmat, ob_index++,
- use_obedit, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob_snap, ob->obmat, ob_index++, use_obedit,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1760,6 +1827,9 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
+ sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
return sctx;
}
@@ -1774,11 +1844,6 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(
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;
}
@@ -1810,10 +1875,8 @@ static void snap_object_data_free(void *sod_v)
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);
- }
+ BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ BLI_memarena_free(sctx->cache.mem_arena);
MEM_freeN(sctx);
}
@@ -1842,10 +1905,15 @@ bool ED_transform_snap_object_project_ray_ex(
Object **r_ob, float r_obmat[4][4])
{
const float depth_range[2] = {0.0f, FLT_MAX};
+
+ SnapData snapdata;
+ snap_data_set(
+ &snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE,
+ NULL, ray_start, ray_start, ray_normal, depth_range);
+
return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
ray_depth, NULL,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -1874,10 +1942,13 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth_prev = ray_depth;
#endif
+ SnapData snapdata;
+ snap_data_set(&snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, NULL,
+ ray_start, ray_start, ray_normal, depth_range);
+
bool retval = snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
&ray_depth, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1956,19 +2027,40 @@ static bool transform_snap_context_project_view3d_mixed_impl(
BLI_assert(snap_to_flag != 0);
BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
- for (int i = 0; i < 3; i++) {
- if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
- if (use_depth == false) {
- ray_depth = BVH_RAYCAST_DIST_MAX;
+ if (use_depth) {
+ const float dist_px_orig = dist_px ? *dist_px : 0;
+ for (int i = 2; i >= 0; i--) {
+ if (snap_to_flag & (1 << i)) {
+ if (i == 0) {
+ BLI_assert(dist_px != NULL);
+ *dist_px = dist_px_orig;
+ }
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ /* 0.01 is a random but small value to prioritizing
+ * the first elements of the loop */
+ ray_depth += 0.01f;
+ is_hit = true;
+ }
}
-
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- is_hit = true;
+ }
+ }
+ else {
+ for (int i = 0; i < 3; i++) {
+ if (snap_to_flag & (1 << i)) {
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ is_hit = true;
+ break;
+ }
}
}
}
@@ -2037,10 +2129,14 @@ bool ED_transform_snap_object_project_view3d_ex(
ray_depth = &ray_depth_fallback;
}
+ SnapData snapdata;
+ const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ snap_data_set(&snapdata, ar, snap_to, view_proj, mval,
+ ray_origin, ray_start, ray_normal, depth_range);
+
return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- mval, ray_origin, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
ray_depth, dist_px,
r_loc, r_no, r_index, NULL, NULL, NULL);
}