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/transform')
-rw-r--r--source/blender/editors/transform/transform.c92
-rw-r--r--source/blender/editors/transform/transform.h5
-rw-r--r--source/blender/editors/transform/transform_constraints.c9
-rw-r--r--source/blender/editors/transform/transform_conversions.c240
-rw-r--r--source/blender/editors/transform/transform_generics.c30
-rw-r--r--source/blender/editors/transform/transform_manipulator.c555
-rw-r--r--source/blender/editors/transform/transform_manipulator2d.c147
-rw-r--r--source/blender/editors/transform/transform_ops.c29
-rw-r--r--source/blender/editors/transform/transform_orientations.c48
-rw-r--r--source/blender/editors/transform/transform_snap.c19
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1454
11 files changed, 1598 insertions, 1030 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 81d8f64045f..4745631e85c 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -52,7 +52,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_memarena.h"
#include "BKE_nla.h"
@@ -66,6 +66,8 @@
#include "BKE_report.h"
#include "BKE_workspace.h"
+#include "DEG_depsgraph.h"
+
#include "BIF_glutil.h"
#include "GPU_immediate.h"
@@ -1731,7 +1733,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
glLineWidth(1.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -1904,7 +1906,7 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo
TransInfo *t = arg;
Scene *scene = t->scene;
SceneLayer *sl = t->scene_layer;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
/* draw autokeyframing hint in the corner
* - only draw if enabled (advanced users may be distracted/annoyed),
@@ -2015,8 +2017,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
View3D *v3d = t->view;
v3d->twmode = t->current_orientation;
- BLI_assert(BKE_workspace_transform_orientation_get_index(CTX_wm_workspace(C), t->custom_orientation)
- == v3d->custom_orientation_index);
+
+ BLI_assert(((v3d->custom_orientation_index == -1) && (t->custom_orientation == NULL)) ||
+ (BKE_workspace_transform_orientation_get_index(
+ CTX_wm_workspace(C), t->custom_orientation) == v3d->custom_orientation_index));
}
}
}
@@ -2621,6 +2625,9 @@ static void constraintTransLim(TransInfo *t, TransData *td)
if (td->con) {
const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(t->context, &eval_ctx);
bConstraintOb cob = {NULL};
bConstraint *con;
@@ -2670,7 +2677,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
}
/* get constraint targets if needed */
- BKE_constraint_targets_for_solving_get(con, &cob, &targets, ctime);
+ BKE_constraint_targets_for_solving_get(&eval_ctx, con, &cob, &targets, ctime);
/* do constraint */
cti->evaluate_constraint(con, &cob, &targets);
@@ -2916,7 +2923,9 @@ static void initBend(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
- calculateCenterCursor(t, t->center);
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ calculateCenterCursor(t, t->center);
+ }
calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
@@ -4097,13 +4106,15 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
{
TransData *td = t->data;
- float mat[3][3], smat[3][3], totmat[3][3];
+ float mat[3][3];
+ float axis[3];
+ float angle;
int i;
- axis_angle_normalized_to_mat3(smat, axis1, angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ mul_v3_v3fl(axis, axis1, angles[0]);
+ madd_v3_v3fl(axis, axis2, angles[1]);
+ angle = normalize_v3(axis);
+ axis_angle_normalized_to_mat3(mat, axis, angle);
for (i = 0; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -4113,10 +4124,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
continue;
if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(smat, axis1, td->factor * angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, td->factor * angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
}
ElementRotation(t, td, mat, t->around);
@@ -7556,7 +7564,7 @@ static void drawVertSlide(TransInfo *t)
glLineWidth(1.0f);
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -8393,8 +8401,15 @@ static void initTimeSlide(TransInfo *t)
TransData *td = t->data;
for (i = 0; i < t->total; i++, td++) {
- if (min > *(td->val)) min = *(td->val);
- if (max < *(td->val)) max = *(td->val);
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float val = *(td->val);
+
+ /* strip/action time to global (mapped) time */
+ if (adt)
+ val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
+
+ if (min > val) min = val;
+ if (max < val) max = val;
}
if (min == max) {
@@ -8469,25 +8484,38 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
*/
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
float cval = t->values[0];
-
- /* apply NLA-mapping to necessary values */
- if (adt)
- cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP);
-
+
/* only apply to data if in range */
if ((sval > minx) && (sval < maxx)) {
float cvalc = CLAMPIS(cval, minx, maxx);
+ float ival = td->ival;
float timefac;
-
+
+ /* NLA mapping magic here works as follows:
+ * - "ival" goes from strip time to global time
+ * - calculation is performed into td->val in global time
+ * (since sval and min/max are all in global time)
+ * - "td->val" then gets put back into strip time
+ */
+ if (adt) {
+ /* strip to global */
+ ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
+ }
+
/* left half? */
- if (td->ival < sval) {
- timefac = (sval - td->ival) / (sval - minx);
+ if (ival < sval) {
+ timefac = (sval - ival) / (sval - minx);
*(td->val) = cvalc - timefac * (cvalc - minx);
}
else {
- timefac = (td->ival - sval) / (maxx - sval);
+ timefac = (ival - sval) / (maxx - sval);
*(td->val) = cvalc + timefac * (maxx - cvalc);
}
+
+ if (adt) {
+ /* global to strip */
+ *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+ }
}
}
}
@@ -8546,9 +8574,11 @@ static void initTimeScale(TransInfo *t)
/* recalculate center2d to use CFRA and mouse Y, since that's
* what is used in time scale */
- t->center[0] = t->scene->r.cfra;
- projectFloatView(t, t->center, center);
- center[1] = t->mouse.imval[1];
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ t->center[0] = t->scene->r.cfra;
+ projectFloatView(t, t->center, center);
+ center[1] = t->mouse.imval[1];
+ }
/* force a reinit with the center2d used here */
initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index d415b3eabeb..92eb31aabe6 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -535,6 +535,9 @@ typedef struct TransInfo {
/* alternative transformation. used to add offset to tracking markers */
#define T_ALT_TRANSFORM (1 << 24)
+ /** #TransInfo.center has been set, don't change it. */
+#define T_OVERRIDE_CENTER (1 << 25)
+
/* TransInfo->modifiers */
#define MOD_CONSTRAINT_SELECT 0x01
#define MOD_PRECISION 0x02
@@ -638,7 +641,7 @@ void restoreBones(TransInfo *t);
/*********************** transform_manipulator.c ********** */
-#define MANIPULATOR_AXIS_LINE_WIDTH 2.0
+#define MANIPULATOR_AXIS_LINE_WIDTH 2.0f
bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 654072766a8..4e409e7f77f 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -735,7 +735,7 @@ void drawConstraint(TransInfo *t)
const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -851,6 +851,13 @@ static void drawObjectConstraint(TransInfo *t)
}
}
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* only draw a constraint line for one point, otherwise we can't see anything */
+ if ((options & DRAWLIGHT) == 0) {
+ break;
+ }
+ }
+
if (t->flag & T_OBJECT) {
copy_v3_v3(co, td->ob->obmat[3]);
axismtx = td->axismtx;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 243788c20b3..166a5805fa1 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -292,7 +292,7 @@ static void createTransTexspace(TransInfo *t)
ID *id;
short *texflag;
- ob = OBACT_NEW;
+ ob = OBACT_NEW(sl);
if (ob == NULL) { // Shouldn't logically happen, but still...
t->total = 0;
@@ -772,29 +772,37 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* -------- Auto-IK ---------- */
/* adjust pose-channel's auto-ik chainlen */
-static void pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
+static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
{
bConstraint *con;
+ bool changed = false;
/* don't bother to search if no valid constraints */
- if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0)
- return;
+ if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
+ return changed;
+ }
/* check if pchan has ik-constraint */
for (con = pchan->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
bKinematicConstraint *data = con->data;
-
+
/* only accept if a temporary one (for auto-ik) */
if (data->flag & CONSTRAINT_IK_TEMP) {
/* chainlen is new chainlen, but is limited by maximum chainlen */
- if ((chainlen == 0) || (chainlen > data->max_rootbone))
+ const int old_rootbone = data->rootbone;
+ if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
data->rootbone = data->max_rootbone;
- else
+ }
+ else {
data->rootbone = chainlen;
+ }
+ changed |= (data->rootbone != old_rootbone);
}
}
}
+
+ return changed;
}
/* change the chain-length of auto-ik */
@@ -810,7 +818,13 @@ void transform_autoik_update(TransInfo *t, short mode)
}
else if (mode == -1) {
/* mode==-1 is from WHEELMOUSEUP... decreases len */
- if (*chainlen > 0) (*chainlen)--;
+ if (*chainlen > 0) {
+ (*chainlen)--;
+ }
+ else {
+ /* IK length did not change, skip updates. */
+ return;
+ }
}
/* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
@@ -818,8 +832,14 @@ void transform_autoik_update(TransInfo *t, short mode)
return;
/* apply to all pose-channels */
+ bool changed = false;
for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan_autoik_adjust(pchan, *chainlen);
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
+ }
+
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(G.main);
}
}
@@ -829,6 +849,7 @@ static void pose_grab_with_ik_clear(Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
+ bool relations_changed = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -842,6 +863,8 @@ static void pose_grab_with_ik_clear(Object *ob)
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
+ relations_changed = true;
+
/* iTaSC needs clear for removed constraints */
BIK_clear_data(ob->pose);
@@ -857,8 +880,10 @@ static void pose_grab_with_ik_clear(Object *ob)
}
}
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(G.main);
+ if (relations_changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(G.main);
+ }
}
/* adds the IK to pchan - returns if added */
@@ -1485,6 +1510,48 @@ static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc
return hdata;
}
+/**
+ * For the purpose of transform code we need to behave as if handles are selected,
+ * even when they aren't (see special case below).
+ */
+static int bezt_select_to_transform_triple_flag(
+ const BezTriple *bezt, const bool hide_handles)
+{
+ int flag = 0;
+
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+ else {
+ flag = (
+ ((bezt->f1 & SELECT) ? (1 << 0) : 0) |
+ ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+ ((bezt->f3 & SELECT) ? (1 << 2) : 0)
+ );
+ }
+
+ /* Special case for auto & aligned handles:
+ * When a center point is being moved without the handles,
+ * leaving the handles stationary makes no sense and only causes strange behavior,
+ * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+ * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+ *
+ * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+ * However that doesn't resolve odd behavior, so best transform the handles in this case.
+ */
+ if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) &&
+ ELEM(bezt->h2, HD_AUTO, HD_ALIGN))
+ {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+
+ return flag;
+}
+
static void createTransCurveVerts(TransInfo *t)
{
Curve *cu = t->obedit->data;
@@ -1502,22 +1569,22 @@ static void createTransCurveVerts(TransInfo *t)
/* to be sure */
if (cu->editnurb == NULL) return;
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
/* count total of vertices, check identical as in 2nd loop for making transdata! */
nurbs = BKE_curve_editNurbs_get(cu);
for (nu = nurbs->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
- if (hide_handles) {
- if (bezt->f2 & SELECT) countsel += 3;
- if (is_prop_edit) count += 3;
- }
- else {
- if (bezt->f1 & SELECT) countsel++;
- if (bezt->f2 & SELECT) countsel++;
- if (bezt->f3 & SELECT) countsel++;
- if (is_prop_edit) count += 3;
- }
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ if (bezt_tx & SEL_F1) { countsel++; }
+ if (bezt_tx & SEL_F2) { countsel++; }
+ if (bezt_tx & SEL_F3) { countsel++; }
+ if (is_prop_edit) count += 3;
+
}
}
}
@@ -1568,10 +1635,10 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f1 & SELECT) && hide_handles == 0))
- {
+ /* Elements that will be transform (not always a match to selection). */
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+
+ if (is_prop_edit || bezt_tx & SEL_F1) {
copy_v3_v3(td->iloc, bezt->vec[0]);
td->loc = bezt->vec[0];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
@@ -1602,7 +1669,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (is_prop_edit || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || bezt_tx & SEL_F2) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1628,7 +1695,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->axismtx, axismtx);
}
- if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0)
+ if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
/* If the middle is selected but the sides arnt, this is needed */
if (hdata == NULL) { /* if the handle was not saved by the previous handle */
hdata = initTransDataCurveHandles(td, bezt);
@@ -1638,10 +1705,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f3 & SELECT) && hide_handles == 0))
- {
+ if (is_prop_edit || bezt_tx & SEL_F3) {
copy_v3_v3(td->iloc, bezt->vec[2]);
td->loc = bezt->vec[2];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
@@ -1696,6 +1760,26 @@ static void createTransCurveVerts(TransInfo *t)
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
if (is_prop_edit || (bp->f1 & SELECT)) {
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+ }
+
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1714,6 +1798,11 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+ }
td++;
count++;
@@ -1729,6 +1818,10 @@ static void createTransCurveVerts(TransInfo *t)
calc_distanceCurveVerts(head, tail - 1);
}
}
+
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
}
/* ********************* lattice *************** */
@@ -1918,7 +2011,7 @@ void flushTransParticles(TransInfo *t)
{
Scene *scene = t->scene;
SceneLayer *sl = t->scene_layer;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
PTCacheEdit *edit = PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = NULL;
@@ -1958,7 +2051,9 @@ void flushTransParticles(TransInfo *t)
point->flag |= PEP_EDIT_RECALC;
}
- PE_update_object(scene, sl, OBACT_NEW, 1);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(t->context, &eval_ctx);
+ PE_update_object(&eval_ctx, scene, sl, OBACT_NEW(sl), 1);
}
/* ********************* mesh ****************** */
@@ -2370,6 +2465,7 @@ static void createTransEditVerts(TransInfo *t)
{
TransData *tob = NULL;
TransDataExtension *tx = NULL;
+ EvaluationContext eval_ctx;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
Mesh *me = t->obedit->data;
BMesh *bm = em->bm;
@@ -2388,6 +2484,10 @@ static void createTransEditVerts(TransInfo *t)
int island_info_tot;
int *island_vert_map = NULL;
+ DEG_evaluation_context_init_from_scene(&eval_ctx,
+ t->scene, t->scene_layer,
+ DAG_EVAL_VIEWPORT);
+
/* Even for translation this is needed because of island-orientation, see: T51651. */
const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
/* Original index of our connected vertex when connected distances are calculated.
@@ -2471,7 +2571,7 @@ static void createTransEditVerts(TransInfo *t)
if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
/* check if we can use deform matrices for modifier from the
* start up to stack, they are more accurate than quats */
- totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos);
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&eval_ctx, t->scene, t->obedit, em, &defmats, &defcos);
}
/* if we still have more modifiers, also do crazyspace
@@ -2484,7 +2584,7 @@ static void createTransEditVerts(TransInfo *t)
if (totleft > 0)
#endif
{
- mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
+ mappedcos = BKE_crazyspace_get_mapped_editverts(&eval_ctx, t->scene, t->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
@@ -2694,7 +2794,7 @@ void flushTransSeq(TransInfo *t)
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
old_start = seq->start;
- new_frame = iroundf(td2d->loc[0]);
+ new_frame = round_fl_to_int(td2d->loc[0]);
switch (tdsq->sel_flag) {
case SELECT:
@@ -2706,7 +2806,7 @@ void flushTransSeq(TransInfo *t)
seq->start = new_frame - tdsq->start_offset;
#endif
if (seq->depth == 0) {
- seq->machine = iroundf(td2d->loc[1]);
+ seq->machine = round_fl_to_int(td2d->loc[1]);
CLAMP(seq->machine, 1, MAXSEQ);
}
break;
@@ -3652,7 +3752,7 @@ void flushTransIntFrameActionData(TransInfo *t)
/* flush data! */
for (i = 0; i < t->total; i++, tfd++) {
- *(tfd->sdata) = iroundf(tfd->val);
+ *(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
@@ -4680,7 +4780,7 @@ void flushTransGraphData(TransInfo *t)
/* if int-values only, truncate to integers */
if (td->flag & TD_INTVALUES)
- td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
+ td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
else
td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
@@ -5310,6 +5410,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
Scene *scene = t->scene;
bool constinv;
bool skip_invert = false;
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(t->context, &eval_ctx);
if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
@@ -5333,7 +5436,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
}
/* update object's loc/rot to get current rigid body transform */
mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
- BKE_object_mat3_to_rot(ob, rot, false);
+ sub_v3_v3(ob->loc, ob->dloc);
+ BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
}
}
@@ -5356,11 +5460,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
if (skip_invert == false && constinv == false) {
ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
- BKE_object_where_is_calc(t->scene, ob);
+ BKE_object_where_is_calc(&eval_ctx, t->scene, ob);
ob->transflag &= ~OB_NO_CONSTRAINTS;
}
else
- BKE_object_where_is_calc(t->scene, ob);
+ BKE_object_where_is_calc(&eval_ctx, t->scene, ob);
td->ob = ob;
@@ -5451,10 +5555,14 @@ static void set_trans_object_base_flags(TransInfo *t)
DEG_scene_relations_update(G.main, t->scene);
/* handle pending update events, otherwise they got copied below */
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init_from_scene(&eval_ctx,
+ t->scene, t->scene_layer,
+ DAG_EVAL_VIEWPORT);
for (base = sl->object_bases.first; base; base = base->next) {
if (base->object->recalc & OB_RECALC_ALL) {
/* TODO(sergey): Ideally, it's not needed. */
- BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object);
+ BKE_object_handle_update(&eval_ctx, t->scene, base->object);
}
}
@@ -5467,8 +5575,8 @@ static void set_trans_object_base_flags(TransInfo *t)
/* if parent selected, deselect */
while (parsel) {
- Base *parbase = BKE_scene_layer_base_find(sl, parsel);
- if (parbase->flag & BASE_SELECTED) {
+ if (parsel->base_flag & BASE_SELECTED) {
+ Base *parbase = BKE_scene_layer_base_find(sl, parsel);
if (parbase) { /* in rare cases this can fail */
if (TESTBASELIB_BGMODE_NEW(parbase)) {
break;
@@ -5494,6 +5602,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
}
+ /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+ DEG_scene_flush_update(G.main, t->scene);
+
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
for (base = sl->object_bases.first; base; base = base->next) {
@@ -5572,6 +5683,7 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DEG_scene_relations_update(G.main, t->scene);
+ DEG_scene_flush_update(G.main, t->scene);
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5652,7 +5764,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D *
}
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT_NEW)
+ if (ob != OBACT_NEW(sl))
do_loc = true;
}
else if (v3d->around == V3D_AROUND_CURSOR)
@@ -5663,7 +5775,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D *
}
else if (tmode == TFM_RESIZE) {
if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT_NEW)
+ if (ob != OBACT_NEW(sl))
do_loc = true;
}
else if (v3d->around == V3D_AROUND_CURSOR)
@@ -5841,7 +5953,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
*/
if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
//ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob);
}
}
else {
@@ -5859,27 +5971,23 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
SpaceClip *sc = t->sa->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingPlaneTrack *plane_track;
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- for (plane_track = plane_tracks_base->first;
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
+ /* Update coordinates of modified plane tracks. */
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
plane_track;
plane_track = plane_track->next)
{
bool do_update = false;
-
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
continue;
}
-
do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
if (do_update == false) {
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int i;
for (i = 0; i < plane_track->point_tracksnr; i++) {
MovieTrackingTrack *track = plane_track->point_tracks[i];
-
if (TRACK_VIEW_SELECTED(sc, track)) {
do_update = true;
break;
@@ -5887,15 +5995,14 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
}
}
}
-
if (do_update) {
BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
}
}
-
- if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
+ if (t->scene->nodetree != NULL) {
+ /* Tracks can be used for stabilization nodes,
+ * flush update for such nodes.
+ */
nodeUpdateID(t->scene->nodetree, &clip->id);
WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
}
@@ -6001,10 +6108,13 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
* */
void special_aftertrans_update(bContext *C, TransInfo *t)
{
+ EvaluationContext eval_ctx;
Object *ob;
// short redrawipo=0, resetslowpar=1;
const bool canceled = (t->state == TRANS_CANCEL);
const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
+
+ CTX_data_eval_ctx(C, &eval_ctx);
/* early out when nothing happened */
if (t->total == 0 || t->mode == TFM_DUMMY)
@@ -6344,7 +6454,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* we need to update the pose otherwise no updates get called during
* transform and the auto-ik is not applied. see [#26164] */
struct Object *pose_ob = t->poseobj;
- BKE_pose_where_is(t->scene, pose_ob);
+ BKE_pose_where_is(&eval_ctx, t->scene, pose_ob);
}
/* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */
@@ -7722,7 +7832,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
float mtx[3][3], smtx[3][3];
const Scene *scene = CTX_data_scene(C);
- const int cfra = CFRA;
+ const int cfra_scene = CFRA;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -7747,7 +7857,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
-
+
for (gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -7803,6 +7913,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
float diff_mat[4][4];
@@ -7819,7 +7930,6 @@ static void createTransGPencil(bContext *C, TransInfo *t)
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame...
*/
- // XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
/* in some weird situations (framelock enabled) return NULL */
@@ -7967,7 +8077,7 @@ void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
SceneLayer *sl = t->scene_layer;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
/* if tests must match recalcData for correct updates */
if (t->options & CTX_TEXTURE) {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index ca9e15f5de4..2bed1dd28f2 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -317,7 +317,7 @@ static bool fcu_test_selected(FCurve *fcu)
/* helper for recalcData() - for Action Editor transforms */
static void recalcData_actedit(TransInfo *t)
{
- SceneLayer *sl= t->scene_layer;
+ SceneLayer *sl = t->scene_layer;
SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
bAnimContext ac = {NULL};
@@ -329,7 +329,7 @@ static void recalcData_actedit(TransInfo *t)
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
ac.scene = t->scene;
ac.scene_layer = t->scene_layer;
- ac.obact = OBACT_NEW;
+ ac.obact = OBACT_NEW(sl);
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -379,7 +379,7 @@ static void recalcData_graphedit(TransInfo *t)
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
ac.scene = t->scene;
ac.scene_layer = t->scene_layer;
- ac.obact = OBACT_NEW;
+ ac.obact = OBACT_NEW(sl);
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -714,6 +714,9 @@ static void recalcData_spaceclip(TransInfo *t)
static void recalcData_objects(TransInfo *t)
{
Base *base = t->scene_layer->basact;
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(t->context, &eval_ctx);
if (t->obedit) {
if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
@@ -898,7 +901,7 @@ static void recalcData_objects(TransInfo *t)
BIK_clear_data(ob->pose);
}
else
- BKE_pose_where_is(t->scene, ob);
+ BKE_pose_where_is(&eval_ctx, t->scene, ob);
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, t->scene_layer, base->object)) {
if (t->state != TRANS_CANCEL) {
@@ -1457,6 +1460,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
#endif
setTransformViewAspect(t, t->aspect);
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->center);
+ mul_v3_v3(t->center, t->aspect);
+ t->flag |= T_OVERRIDE_CENTER;
+ }
+
setTransformViewMatrices(t);
initNumInput(&t->num);
}
@@ -1790,7 +1800,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
else if (t->flag & T_POSE) {
SceneLayer *sl = t->scene_layer;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
if (ob) {
bPoseChannel *pchan = BKE_pose_channel_active(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
@@ -1810,8 +1820,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
else {
/* object mode */
SceneLayer *sl = t->scene_layer;
- Object *ob = OBACT_NEW;
- Base *base = BASACT_NEW;
+ Object *ob = OBACT_NEW(sl);
+ Base *base = BASACT_NEW(sl);
if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
copy_v3_v3(r_center, ob->obmat[3]);
ok = true;
@@ -1858,7 +1868,9 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
void calculateCenter(TransInfo *t)
{
- calculateCenter_FromAround(t, t->around, t->center);
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ calculateCenter_FromAround(t, t->around, t->center);
+ }
calculateCenterGlobal(t, t->center, t->center_global);
/* avoid calculating again */
@@ -1872,7 +1884,7 @@ void calculateCenter(TransInfo *t)
calculateCenter2D(t);
/* for panning from cameraview */
- if (t->flag & T_OBJECT) {
+ if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
if (t->flag & T_CAMERA) {
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 0f5f2f02e84..c0c7c922061 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -86,6 +86,8 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+// #define USE_AXIS_BOUNDS
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -114,27 +116,31 @@ enum {
MAN_AXIS_TRANS_Z,
MAN_AXIS_TRANS_C,
+ MAN_AXIS_TRANS_XY,
+ MAN_AXIS_TRANS_YZ,
+ MAN_AXIS_TRANS_ZX,
+#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X
+#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1)
+
MAN_AXIS_ROT_X,
MAN_AXIS_ROT_Y,
MAN_AXIS_ROT_Z,
MAN_AXIS_ROT_C,
MAN_AXIS_ROT_T, /* trackball rotation */
+#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X
+#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1)
MAN_AXIS_SCALE_X,
MAN_AXIS_SCALE_Y,
MAN_AXIS_SCALE_Z,
MAN_AXIS_SCALE_C,
-
- /* special */
- MAN_AXIS_TRANS_XY,
- MAN_AXIS_TRANS_YZ,
- MAN_AXIS_TRANS_ZX,
-
MAN_AXIS_SCALE_XY,
MAN_AXIS_SCALE_YZ,
MAN_AXIS_SCALE_ZX,
+#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X
+#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1)
- MAN_AXIS_LAST,
+ MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END,
};
/* axis types */
@@ -148,29 +154,19 @@ enum {
typedef struct ManipulatorGroup {
bool all_hidden;
- struct wmManipulator *translate_x,
- *translate_y,
- *translate_z,
- *translate_xy,
- *translate_yz,
- *translate_zx,
- *translate_c,
-
- *rotate_x,
- *rotate_y,
- *rotate_z,
- *rotate_c,
- *rotate_t, /* trackball rotation */
-
- *scale_x,
- *scale_y,
- *scale_z,
- *scale_xy,
- *scale_yz,
- *scale_zx,
- *scale_c;
+ struct wmManipulator *manipulators[MAN_AXIS_LAST];
} ManipulatorGroup;
+struct TransformBounds {
+ float center[3]; /* Center for transform widget. */
+ float min[3], max[3]; /* Boundbox of selection for transform widget. */
+
+#ifdef USE_AXIS_BOUNDS
+ /* Normalized axis */
+ float axis[3][3];
+ float axis_min[3], axis_max[3];
+#endif
+};
/* **************** Utilities **************** */
@@ -189,93 +185,78 @@ typedef struct ManipulatorGroup {
static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx)
{
BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
-
- switch (axis_idx) {
- case MAN_AXIS_TRANS_X:
- return man->translate_x;
- case MAN_AXIS_TRANS_Y:
- return man->translate_y;
- case MAN_AXIS_TRANS_Z:
- return man->translate_z;
- case MAN_AXIS_TRANS_XY:
- return man->translate_xy;
- case MAN_AXIS_TRANS_YZ:
- return man->translate_yz;
- case MAN_AXIS_TRANS_ZX:
- return man->translate_zx;
- case MAN_AXIS_TRANS_C:
- return man->translate_c;
- case MAN_AXIS_ROT_X:
- return man->rotate_x;
- case MAN_AXIS_ROT_Y:
- return man->rotate_y;
- case MAN_AXIS_ROT_Z:
- return man->rotate_z;
- case MAN_AXIS_ROT_C:
- return man->rotate_c;
- case MAN_AXIS_ROT_T:
- return man->rotate_t;
- case MAN_AXIS_SCALE_X:
- return man->scale_x;
- case MAN_AXIS_SCALE_Y:
- return man->scale_y;
- case MAN_AXIS_SCALE_Z:
- return man->scale_z;
- case MAN_AXIS_SCALE_XY:
- return man->scale_xy;
- case MAN_AXIS_SCALE_YZ:
- return man->scale_yz;
- case MAN_AXIS_SCALE_ZX:
- return man->scale_zx;
- case MAN_AXIS_SCALE_C:
- return man->scale_c;
- }
-
- return NULL;
+ return man->manipulators[axis_idx];
}
-static short manipulator_get_axis_type(const ManipulatorGroup *man, const wmManipulator *axis)
+static short manipulator_get_axis_type(const int axis_idx)
{
- if (ELEM(axis, man->translate_x, man->translate_y, man->translate_z, man->translate_c,
- man->translate_xy, man->translate_yz, man->translate_zx))
- {
+ if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
return MAN_AXES_TRANSLATE;
}
- else if (ELEM(axis, man->rotate_x, man->rotate_y, man->rotate_z, man->rotate_c, man->rotate_t)) {
+ if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
return MAN_AXES_ROTATE;
}
- else {
+ if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) {
return MAN_AXES_SCALE;
}
+ BLI_assert(0);
+ return -1;
}
-/* get index within axis type, so that x == 0, y == 1 and z == 2, no matter which axis type */
-static uint manipulator_index_normalize(const int axis_idx)
+static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane)
{
- if (axis_idx > MAN_AXIS_TRANS_ZX) {
- return axis_idx - 16;
- }
- else if (axis_idx > MAN_AXIS_SCALE_C) {
- return axis_idx - 13;
- }
- else if (axis_idx > MAN_AXIS_ROT_T) {
- return axis_idx - 9;
- }
- else if (axis_idx > MAN_AXIS_TRANS_C) {
- return axis_idx - 4;
- }
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_SCALE_YZ:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_SCALE_X:
+ return 0;
+
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_ZX:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_SCALE_Y:
+ return 1;
- return axis_idx;
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_SCALE_XY:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_ROT_Z:
+ case MAN_AXIS_SCALE_Z:
+ return 2;
+ }
+ return 3;
}
static bool manipulator_is_axis_visible(
const View3D *v3d, const RegionView3D *rv3d,
const float idot[3], const int axis_type, const int axis_idx)
{
- const uint aidx_norm = manipulator_index_normalize(axis_idx);
+ bool is_plane = false;
+ const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
/* don't draw axis perpendicular to the view */
- if (aidx_norm < 3 && idot[aidx_norm] < TW_AXIS_DOT_MIN) {
- return false;
+ if (aidx_norm < 3) {
+ float idot_axis = idot[aidx_norm];
+ if (is_plane) {
+ idot_axis = 1.0f - idot_axis;
+ }
+ if (idot_axis < TW_AXIS_DOT_MIN) {
+ return false;
+ }
}
if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) ||
@@ -351,10 +332,14 @@ static void manipulator_get_axis_color(
const float alpha_hi = 1.0f;
float alpha_fac;
- const int axis_idx_norm = manipulator_index_normalize(axis_idx);
+ bool is_plane = false;
+ const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
/* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */
if (axis_idx_norm < 3) {
- const float idot_axis = idot[axis_idx_norm];
+ float idot_axis = idot[axis_idx_norm];
+ if (is_plane) {
+ idot_axis = 1.0f - idot_axis;
+ }
alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ?
1.0f : (idot_axis < TW_AXIS_DOT_MIN) ?
0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
@@ -441,14 +426,18 @@ static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3])
/* **************** Preparation Stuff **************** */
/* transform widget center calc helper for below */
-static void calc_tw_center(Scene *scene, const float co[3])
+static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
{
- float *twcent = scene->twcent;
- float *min = scene->twmin;
- float *max = scene->twmax;
+ minmax_v3v3_v3(tbounds->min, tbounds->max, co);
+ add_v3_v3(tbounds->center, co);
- minmax_v3v3_v3(min, max, co);
- add_v3_v3(twcent, co);
+#ifdef USE_AXIS_BOUNDS
+ for (int i = 0; i < 3; i++) {
+ const float d = dot_v3v3(tbounds->axis[i], co);
+ tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]);
+ tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]);
+ }
+#endif
}
static void protectflag_to_drawflags(short protectflag, short *drawflags)
@@ -593,7 +582,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
/* centroid, boundbox, of selection */
/* returns total items selected */
-static int calc_manipulator_stats(const bContext *C)
+static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -603,7 +592,7 @@ static int calc_manipulator_stats(const bContext *C)
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
Base *base;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
int a, totsel = 0;
@@ -613,10 +602,88 @@ static int calc_manipulator_stats(const bContext *C)
rv3d->twdrawflag = 0xFFFF;
+
+ /* global, local or normal orientation?
+ * if we could check 'totsel' now, this should be skipped with no selection. */
+ if (ob && !is_gp_edit) {
+
+ switch (v3d->twmode) {
+
+ case V3D_MANIP_GLOBAL:
+ {
+ break; /* nothing to do */
+ }
+ case V3D_MANIP_GIMBAL:
+ {
+ float mat[3][3];
+ if (gimbal_axis(ob, mat)) {
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ /* if not gimbal, fall through to normal */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_MANIP_NORMAL:
+ {
+ if (obedit || ob->mode & OB_MODE_POSE) {
+ float mat[3][3];
+ ED_getTransformOrientationMatrix(C, mat, v3d->around);
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ /* no break we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_MANIP_LOCAL:
+ {
+ if (ob->mode & OB_MODE_POSE) {
+ /* each bone moves on its own local axis, but to avoid confusion,
+ * use the active pones axis for display [#33575], this works as expected on a single bone
+ * and users who select many bones will understand whats going on and what local means
+ * when they start transforming */
+ float mat[3][3];
+ ED_getTransformOrientationMatrix(C, mat, v3d->around);
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ copy_m4_m4(rv3d->twmat, ob->obmat);
+ normalize_m4(rv3d->twmat);
+ break;
+ }
+ case V3D_MANIP_VIEW:
+ {
+ float mat[3][3];
+ copy_m3_m4(mat, rv3d->viewinv);
+ normalize_m3(mat);
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ case V3D_MANIP_CUSTOM:
+ {
+ TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find(
+ CTX_wm_workspace(C), v3d->custom_orientation_index);
+ float mat[3][3];
+
+ if (applyTransformOrientation(custom_orientation, mat, NULL)) {
+ copy_m4_m3(rv3d->twmat, mat);
+ }
+ break;
+ }
+ }
+ }
+
/* transform widget centroid/center */
- INIT_MINMAX(scene->twmin, scene->twmax);
- zero_v3(scene->twcent);
-
+ INIT_MINMAX(tbounds->min, tbounds->max);
+ zero_v3(tbounds->center);
+
+#ifdef USE_AXIS_BOUNDS
+ copy_m3_m4(tbounds->axis, rv3d->twmat);
+ for (int i = 0; i < 3; i++) {
+ tbounds->axis_min[i] = +FLT_MAX;
+ tbounds->axis_max[i] = -FLT_MAX;
+ }
+#endif
+
if (is_gp_edit) {
float diff_mat[4][4];
float fpt[3];
@@ -645,12 +712,12 @@ static int calc_manipulator_stats(const bContext *C)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
- calc_tw_center(scene, &pt->x);
+ calc_tw_center(tbounds, &pt->x);
totsel++;
}
else {
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- calc_tw_center(scene, fpt);
+ calc_tw_center(tbounds, fpt);
totsel++;
}
}
@@ -663,7 +730,7 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */
}
}
else if (obedit) {
@@ -676,7 +743,7 @@ static int calc_manipulator_stats(const bContext *C)
/* USE LAST SELECTE WITH ACTIVE */
if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
BM_editselection_center(&ese, vec);
- calc_tw_center(scene, vec);
+ calc_tw_center(tbounds, vec);
totsel = 1;
}
else {
@@ -689,7 +756,7 @@ static int calc_manipulator_stats(const bContext *C)
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
totsel++;
- calc_tw_center(scene, eve->co);
+ calc_tw_center(tbounds, eve->co);
}
}
}
@@ -702,13 +769,13 @@ static int calc_manipulator_stats(const bContext *C)
if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
/* doesn't check selection or visibility intentionally */
if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(scene, ebo->tail);
+ calc_tw_center(tbounds, ebo->tail);
totsel++;
}
if ((ebo->flag & BONE_ROOTSEL) ||
((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */
{
- calc_tw_center(scene, ebo->head);
+ calc_tw_center(tbounds, ebo->head);
totsel++;
}
protectflag_to_drawflags_ebone(rv3d, ebo);
@@ -717,7 +784,7 @@ static int calc_manipulator_stats(const bContext *C)
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (EBONE_VISIBLE(arm, ebo)) {
if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(scene, ebo->tail);
+ calc_tw_center(tbounds, ebo->tail);
totsel++;
}
if ((ebo->flag & BONE_ROOTSEL) &&
@@ -727,7 +794,7 @@ static int calc_manipulator_stats(const bContext *C)
(ebo->parent->flag & BONE_TIPSEL) &&
EBONE_VISIBLE(arm, ebo->parent)) == 0)
{
- calc_tw_center(scene, ebo->head);
+ calc_tw_center(tbounds, ebo->head);
totsel++;
}
if (ebo->flag & BONE_SELECTED) {
@@ -742,7 +809,7 @@ static int calc_manipulator_stats(const bContext *C)
float center[3];
if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
- calc_tw_center(scene, center);
+ calc_tw_center(tbounds, center);
totsel++;
}
else {
@@ -763,21 +830,21 @@ static int calc_manipulator_stats(const bContext *C)
*/
if (cu->drawflag & CU_HIDE_HANDLES) {
if (bezt->f2 & SELECT) {
- calc_tw_center(scene, bezt->vec[1]);
+ calc_tw_center(tbounds, bezt->vec[1]);
totsel++;
}
}
else if (bezt->f2 & SELECT) {
- calc_tw_center(scene, bezt->vec[1]);
+ calc_tw_center(tbounds, bezt->vec[1]);
totsel++;
}
else {
if (bezt->f1 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
+ calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
totsel++;
}
if (bezt->f3 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
+ calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
totsel++;
}
}
@@ -789,7 +856,7 @@ static int calc_manipulator_stats(const bContext *C)
a = nu->pntsu * nu->pntsv;
while (a--) {
if (bp->f1 & SELECT) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
bp++;
@@ -804,13 +871,13 @@ static int calc_manipulator_stats(const bContext *C)
MetaElem *ml;
if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
- calc_tw_center(scene, &ml->x);
+ calc_tw_center(tbounds, &ml->x);
totsel++;
}
else {
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) {
- calc_tw_center(scene, &ml->x);
+ calc_tw_center(tbounds, &ml->x);
totsel++;
}
}
@@ -821,7 +888,7 @@ static int calc_manipulator_stats(const bContext *C)
BPoint *bp;
if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
else {
@@ -829,7 +896,7 @@ static int calc_manipulator_stats(const bContext *C)
a = lt->pntsu * lt->pntsv * lt->pntsw;
while (a--) {
if (bp->f1 & SELECT) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
bp++;
@@ -839,10 +906,10 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(obedit->obmat, scene->twcent);
- mul_m4_v3(obedit->obmat, scene->twmin);
- mul_m4_v3(obedit->obmat, scene->twmax);
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(obedit->obmat, tbounds->center);
+ mul_m4_v3(obedit->obmat, tbounds->min);
+ mul_m4_v3(obedit->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
@@ -854,7 +921,7 @@ static int calc_manipulator_stats(const bContext *C)
/* doesn't check selection or visibility intentionally */
Bone *bone = pchan->bone;
if (bone) {
- calc_tw_center(scene, pchan->pose_head);
+ calc_tw_center(tbounds, pchan->pose_head);
protectflag_to_drawflags_pchan(rv3d, pchan);
totsel = 1;
ok = true;
@@ -868,7 +935,7 @@ static int calc_manipulator_stats(const bContext *C)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
- calc_tw_center(scene, pchan->pose_head);
+ calc_tw_center(tbounds, pchan->pose_head);
protectflag_to_drawflags_pchan(rv3d, pchan);
}
}
@@ -877,10 +944,10 @@ static int calc_manipulator_stats(const bContext *C)
}
if (ok) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(ob->obmat, scene->twcent);
- mul_m4_v3(ob->obmat, scene->twmin);
- mul_m4_v3(ob->obmat, scene->twmax);
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
@@ -899,7 +966,7 @@ static int calc_manipulator_stats(const bContext *C)
for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
if (ek->flag & PEK_SELECT) {
- calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
+ calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
totsel++;
}
}
@@ -907,21 +974,21 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel)
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
}
}
else {
/* we need the one selected object, if its not active */
- base = BASACT_NEW;
- ob = OBACT_NEW;
+ base = BASACT_NEW(sl);
+ ob = OBACT_NEW(sl);
if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
for (base = sl->object_bases.first; base; base = base->next) {
if (TESTBASELIB_NEW(base)) {
if (ob == NULL)
ob = base->object;
- calc_tw_center(scene, base->object->obmat[3]);
+ calc_tw_center(tbounds, base->object->obmat[3]);
protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
totsel++;
}
@@ -929,77 +996,12 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
}
}
- /* global, local or normal orientation? */
- if (ob && totsel && !is_gp_edit) {
-
- switch (v3d->twmode) {
-
- case V3D_MANIP_GLOBAL:
- {
- break; /* nothing to do */
- }
- case V3D_MANIP_GIMBAL:
- {
- float mat[3][3];
- if (gimbal_axis(ob, mat)) {
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- /* if not gimbal, fall through to normal */
- ATTR_FALLTHROUGH;
- }
- case V3D_MANIP_NORMAL:
- {
- if (obedit || ob->mode & OB_MODE_POSE) {
- float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, v3d->around);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- /* no break we define 'normal' as 'local' in Object mode */
- ATTR_FALLTHROUGH;
- }
- case V3D_MANIP_LOCAL:
- {
- if (ob->mode & OB_MODE_POSE) {
- /* each bone moves on its own local axis, but to avoid confusion,
- * use the active pones axis for display [#33575], this works as expected on a single bone
- * and users who select many bones will understand whats going on and what local means
- * when they start transforming */
- float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, v3d->around);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- copy_m4_m4(rv3d->twmat, ob->obmat);
- normalize_m4(rv3d->twmat);
- break;
- }
- case V3D_MANIP_VIEW:
- {
- float mat[3][3];
- copy_m3_m4(mat, rv3d->viewinv);
- normalize_m3(mat);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- case V3D_MANIP_CUSTOM:
- {
- TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find(
- CTX_wm_workspace(C), v3d->custom_orientation_index);
- float mat[3][3];
-
- if (applyTransformOrientation(custom_orientation, mat, NULL)) {
- copy_m4_m3(rv3d->twmat, mat);
- }
- break;
- }
- }
-
+ if (totsel == 0) {
+ unit_m4(rv3d->twmat);
}
return totsel;
@@ -1015,7 +1017,8 @@ static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3])
}
}
-static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D *rv3d)
+static void manipulator_prepare_mat(
+ const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds)
{
Scene *scene = CTX_data_scene(C);
SceneLayer *sl = CTX_data_scene_layer(C);
@@ -1024,23 +1027,23 @@ static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D
case V3D_AROUND_CENTER_BOUNDS:
case V3D_AROUND_ACTIVE:
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT_NEW;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = OBACT_NEW(sl);
- if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
- ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
- (!(ob->mode & OB_MODE_POSE)))
- {
- copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
- }
- else {
- mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
- }
- break;
+ if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
+ ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ (!(ob->mode & OB_MODE_POSE)))
+ {
+ copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
+ }
+ else {
+ mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max);
+ }
+ break;
}
case V3D_AROUND_LOCAL_ORIGINS:
case V3D_AROUND_CENTER_MEAN:
- copy_v3_v3(rv3d->twmat[3], scene->twcent);
+ copy_v3_v3(rv3d->twmat[3], tbounds->center);
break;
case V3D_AROUND_CURSOR:
copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
@@ -1090,48 +1093,48 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true);
-#define MANIPULATOR_NEW_ARROW(v, name, draw_style) { \
- v = WM_manipulator_new_ptr(wt_arrow, mgroup, name, NULL); \
- RNA_enum_set((v)->ptr, "draw_style", draw_style); \
+#define MANIPULATOR_NEW_ARROW(v, draw_style) { \
+ man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \
+ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
} ((void)0)
-#define MANIPULATOR_NEW_DIAL(v, name, draw_options) { \
- v = WM_manipulator_new_ptr(wt_dial, mgroup, name, NULL); \
- RNA_enum_set((v)->ptr, "draw_options", draw_options); \
+#define MANIPULATOR_NEW_DIAL(v, draw_options) { \
+ man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \
+ RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \
} ((void)0)
-#define MANIPULATOR_NEW_PRIM(v, name, draw_style) { \
- v = WM_manipulator_new_ptr(wt_prim, mgroup, name, NULL); \
- RNA_enum_set((v)->ptr, "draw_style", draw_style); \
+#define MANIPULATOR_NEW_PRIM(v, draw_style) { \
+ man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \
+ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
} ((void)0)
/* add/init widgets - order matters! */
- MANIPULATOR_NEW_DIAL(man->rotate_t, "rotate_t", ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL);
- MANIPULATOR_NEW_DIAL(man->scale_c, "scale_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- MANIPULATOR_NEW_ARROW(man->scale_x, "scale_x", ED_MANIPULATOR_ARROW_STYLE_BOX);
- MANIPULATOR_NEW_ARROW(man->scale_y, "scale_y", ED_MANIPULATOR_ARROW_STYLE_BOX);
- MANIPULATOR_NEW_ARROW(man->scale_z, "scale_z", ED_MANIPULATOR_ARROW_STYLE_BOX);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX);
- MANIPULATOR_NEW_PRIM(man->scale_xy, "scale_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- MANIPULATOR_NEW_PRIM(man->scale_yz, "scale_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- MANIPULATOR_NEW_PRIM(man->scale_zx, "scale_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- MANIPULATOR_NEW_DIAL(man->rotate_x, "rotate_x", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
- MANIPULATOR_NEW_DIAL(man->rotate_y, "rotate_y", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
- MANIPULATOR_NEW_DIAL(man->rotate_z, "rotate_z", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
/* init screen aligned widget last here, looks better, behaves better */
- MANIPULATOR_NEW_DIAL(man->rotate_c, "rotate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- MANIPULATOR_NEW_DIAL(man->translate_c, "translate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
+ MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- MANIPULATOR_NEW_ARROW(man->translate_x, "translate_x", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
- MANIPULATOR_NEW_ARROW(man->translate_y, "translate_y", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
- MANIPULATOR_NEW_ARROW(man->translate_z, "translate_z", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
- MANIPULATOR_NEW_PRIM(man->translate_xy, "translate_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- MANIPULATOR_NEW_PRIM(man->translate_yz, "translate_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- MANIPULATOR_NEW_PRIM(man->translate_zx, "translate_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
return man;
}
@@ -1139,20 +1142,25 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
/**
* Custom handler for manipulator widgets
*/
-static void manipulator_modal(
- bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
+static int manipulator_modal(
+ bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
+ eWM_ManipulatorTweak UNUSED(tweak_flag))
{
const ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
+ struct TransformBounds tbounds;
- if (calc_manipulator_stats(C)) {
- manipulator_prepare_mat(C, v3d, rv3d);
+
+ if (calc_manipulator_stats(C, &tbounds)) {
+ manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]);
}
ED_region_tag_redraw(ar);
+
+ return OPERATOR_RUNNING_MODAL;
}
static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
@@ -1168,7 +1176,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
MAN_ITER_AXES_BEGIN(axis, axis_idx)
{
- const short axis_type = manipulator_get_axis_type(man, axis);
+ const short axis_type = manipulator_get_axis_type(axis_idx);
int constraint_axis[3] = {1, 0, 0};
PointerRNA *ptr;
@@ -1177,7 +1185,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
/* custom handler! */
WM_manipulator_set_fn_custom_modal(axis, manipulator_modal);
- switch(axis_idx) {
+ switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
@@ -1204,6 +1212,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
WM_manipulator_set_scale(axis, 0.07f);
WM_manipulator_set_matrix_offset_location(axis, ofs);
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
break;
}
case MAN_AXIS_TRANS_C:
@@ -1228,7 +1237,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
if (ot_store.translate == NULL) {
ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
}
- ptr = WM_manipulator_set_operator(axis, ot_store.translate, NULL);
+ ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL);
break;
case MAN_AXES_ROTATE:
{
@@ -1245,7 +1254,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
}
ot_rotate = ot_store.rotate;
}
- ptr = WM_manipulator_set_operator(axis, ot_rotate, NULL);
+ ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL);
break;
}
case MAN_AXES_SCALE:
@@ -1253,7 +1262,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat
if (ot_store.resize == NULL) {
ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
}
- ptr = WM_manipulator_set_operator(axis, ot_store.resize, NULL);
+ ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL);
break;
}
}
@@ -1277,19 +1286,20 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou
ARegion *ar = CTX_wm_region(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
+ struct TransformBounds tbounds;
/* skip, we don't draw anything anyway */
- if ((man->all_hidden = (calc_manipulator_stats(C) == 0)))
+ if ((man->all_hidden = (calc_manipulator_stats(C, &tbounds) == 0)))
return;
- manipulator_prepare_mat(C, v3d, rv3d);
+ manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
/* *** set properties for axes *** */
MAN_ITER_AXES_BEGIN(axis, axis_idx)
{
- const short axis_type = manipulator_get_axis_type(man, axis);
- const int aidx_norm = manipulator_index_normalize(axis_idx);
+ const short axis_type = manipulator_get_axis_type(axis_idx);
+ const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL);
WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]);
@@ -1309,6 +1319,7 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou
WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
RNA_float_set(axis->ptr, "length", len);
WM_manipulator_set_matrix_offset_location(axis, start_co);
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
break;
}
case MAN_AXIS_ROT_X:
@@ -1323,8 +1334,8 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX:
{
- const float *y_axis = rv3d->twmat[aidx_norm + 1 > 2 ? 0 : aidx_norm + 1];
- const float *z_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
+ const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
+ const float *z_axis = rv3d->twmat[aidx_norm];
WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
break;
}
@@ -1358,7 +1369,7 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato
MAN_ITER_AXES_BEGIN(axis, axis_idx)
{
- const short axis_type = manipulator_get_axis_type(man, axis);
+ const short axis_type = manipulator_get_axis_type(axis_idx);
/* XXX maybe unset _HIDDEN flag on redraw? */
if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) {
WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false);
@@ -1368,10 +1379,10 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato
continue;
}
- float col[4], col_hi[4];
- manipulator_get_axis_color(axis_idx, idot, col, col_hi);
- WM_manipulator_set_color(axis, col);
- WM_manipulator_set_color_highlight(axis, col_hi);
+ float color[4], color_hi[4];
+ manipulator_get_axis_color(axis_idx, idot, color, color_hi);
+ WM_manipulator_set_color(axis, color);
+ WM_manipulator_set_color_highlight(axis, color_hi);
switch (axis_idx) {
case MAN_AXIS_TRANS_C:
diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c
index 104675cb1a8..94f425eb9f0 100644
--- a/source/blender/editors/transform/transform_manipulator2d.c
+++ b/source/blender/editors/transform/transform_manipulator2d.c
@@ -73,8 +73,13 @@ typedef struct ManipulatorGroup2D {
wmManipulator *translate_x,
*translate_y;
+ wmManipulator *cage;
+
/* Current origin in view space, used to update widget origin for possible view changes */
float origin[2];
+ float min[2];
+ float max[2];
+
} ManipulatorGroup2D;
@@ -131,11 +136,18 @@ static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float
static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup)
{
const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true);
+ const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true);
ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__);
- man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_x", NULL);
- man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_y", NULL);
+ man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
+ man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
+ man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL);
+
+ RNA_enum_set(man->cage->ptr, "transform",
+ ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE |
+ ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE |
+ ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE);
return man;
}
@@ -143,17 +155,24 @@ static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup)
/**
* Calculates origin in view space, use with #manipulator2d_origin_to_region.
*/
-static void manipulator2d_calc_origin(const bContext *C, float *r_origin)
+static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
- if (sima->around == V3D_AROUND_CURSOR) {
- copy_v2_v2(r_origin, sima->cursor);
+ float min_buf[2], max_buf[2];
+ if (r_min == NULL) {
+ r_min = min_buf;
}
- else {
- ED_uvedit_center(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_origin, sima->around);
+ if (r_max == NULL) {
+ r_max = max_buf;
+ }
+
+ if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) {
+ zero_v2(r_min);
+ zero_v2(r_max);
}
+ mid_v2_v2v2(r_center, r_min, r_max);
}
/**
@@ -167,17 +186,20 @@ BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin)
/**
* Custom handler for manipulator widgets
*/
-static void manipulator2d_modal(
- bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
+static int manipulator2d_modal(
+ bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
+ eWM_ManipulatorTweak UNUSED(tweak_flag))
{
ARegion *ar = CTX_wm_region(C);
float origin[3];
- manipulator2d_calc_origin(C, origin);
+ manipulator2d_calc_bounds(C, origin, NULL, NULL);
manipulator2d_origin_to_region(ar, origin);
WM_manipulator_set_matrix_location(widget, origin);
ED_region_tag_redraw(ar);
+
+ return OPERATOR_RUNNING_MODAL;
}
void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
@@ -190,8 +212,8 @@ void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulator
{
const float offset[3] = {0.0f, 0.2f};
- float col[4], col_hi[4];
- manipulator2d_get_axis_color(axis_idx, col, col_hi);
+ float color[4], color_hi[4];
+ manipulator2d_get_axis_color(axis_idx, color, color_hi);
/* custom handler! */
WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal);
@@ -201,41 +223,128 @@ void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulator
WM_manipulator_set_matrix_offset_location(axis, offset);
WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
WM_manipulator_set_scale(axis, U.manipulator_size);
- WM_manipulator_set_color(axis, col);
- WM_manipulator_set_color_highlight(axis, col_hi);
+ WM_manipulator_set_color(axis, color);
+ WM_manipulator_set_color_highlight(axis, color_hi);
/* assign operator */
- PointerRNA *ptr = WM_manipulator_set_operator(axis, ot_translate, NULL);
- int constraint[3] = {0.0f};
+ PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL);
+ int constraint[3] = {0};
constraint[(axis_idx + 1) % 2] = 1;
if (RNA_struct_find_property(ptr, "constraint_axis"))
RNA_boolean_set_array(ptr, "constraint_axis", constraint);
RNA_boolean_set(ptr, "release_confirm", 1);
}
MAN2D_ITER_AXES_END;
+
+ {
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
+ PointerRNA *ptr;
+
+ /* assign operator */
+ ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL);
+ RNA_boolean_set(ptr, "release_confirm", 1);
+
+ int constraint_x[3] = {1, 0, 0};
+ int constraint_y[3] = {0, 1, 0};
+
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
+ PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
+ PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ }
}
void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup)
{
ManipulatorGroup2D *man = mgroup->customdata;
float origin[3];
-
- manipulator2d_calc_origin(C, origin);
+ manipulator2d_calc_bounds(C, origin, man->min, man->max);
copy_v2_v2(man->origin, origin);
+ bool show_cage = !equals_v2v2(man->min, man->max);
+
+ if (show_cage) {
+ man->cage->flag &= ~WM_MANIPULATOR_HIDDEN;
+ man->translate_x->flag |= WM_MANIPULATOR_HIDDEN;
+ man->translate_y->flag |= WM_MANIPULATOR_HIDDEN;
+ }
+ else {
+ man->cage->flag |= WM_MANIPULATOR_HIDDEN;
+ man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN;
+ man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN;
+ }
+
+ if (show_cage) {
+ wmManipulatorOpElem *mpop;
+ float mid[2];
+ const float *min = man->min;
+ const float *max = man->max;
+ mid_v2_v2v2(mid, min, max);
+
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X);
+ PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override");
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
+
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
+
+ mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE);
+ RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ }
}
void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
{
+ ARegion *ar = CTX_wm_region(C);
ManipulatorGroup2D *man = mgroup->customdata;
float origin[3] = {UNPACK2(man->origin), 0.0f};
+ float origin_aa[3] = {UNPACK2(man->origin), 0.0f};
- manipulator2d_origin_to_region(CTX_wm_region(C), origin);
+ manipulator2d_origin_to_region(ar, origin);
MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
{
WM_manipulator_set_matrix_location(axis, origin);
}
MAN2D_ITER_AXES_END;
+
+ UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space);
+ WM_manipulator_set_matrix_offset_location(man->cage, origin_aa);
+ man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]);
+ man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]);
}
/* TODO (Julian)
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index dba442259d1..d7ed80841da 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -559,6 +559,14 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming");
}
+ if (flags & P_CENTER) {
+ /* For manipulators that define their own center. */
+ prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)");
+ }
+
if ((flags & P_NO_DEFAULTS) == 0) {
// Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit
/*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button");
@@ -606,7 +614,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
}
static int skin_resize_poll(bContext *C)
@@ -657,7 +666,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
/* Maybe we could use float_vector_xyz here too? */
RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
@@ -677,7 +686,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
@@ -720,7 +730,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
@@ -761,7 +771,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER);
}
static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
@@ -804,7 +814,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
@@ -822,7 +832,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
@@ -985,7 +995,8 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
void transform_operatortypes(void)
@@ -1050,6 +1061,8 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element");
+ /* Will fall-through to texture-space transform. */
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_transform_axis_target", TKEY, KM_PRESS, KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, OP_TRANSLATION, TKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "texture_space", true);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index c0db83ffa5e..e91db762eb1 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -581,7 +581,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
Base *base;
- Object *ob = OBACT_NEW;
+ Object *ob = OBACT_NEW(sl);
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
@@ -809,15 +809,21 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = obedit->data;
Nurb *nu = NULL;
- BezTriple *bezt = NULL;
int a;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) {
+ void *vert_act = NULL;
+ if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) {
if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = vert_act;
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
BKE_nurb_bezt_calc_plane(nu, bezt, plane);
}
+ else {
+ BPoint *bp = vert_act;
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+ }
}
else {
const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
@@ -825,7 +831,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
+ BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
short flag = 0;
@@ -877,6 +883,36 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
bezt++;
}
}
+ else if (nu->bp && (nu->pntsv == 1)) {
+ BPoint *bp = nu->bp;
+ a = nu->pntsu;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ float tvec[3];
+
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+
+ const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT);
+ const bool is_next_sel = bp_next && (bp_next->f1 & SELECT);
+ if (is_prev_sel == false && is_next_sel == false) {
+ /* Isolated, add based on surrounding */
+ BKE_nurb_bpoint_calc_normal(nu, bp, tvec);
+ add_v3_v3(normal, tvec);
+ }
+ else if (is_next_sel) {
+ /* A segment, add the edge normal */
+ sub_v3_v3v3(tvec, bp->vec, bp_next->vec );
+ normalize_v3(tvec);
+ add_v3_v3(normal, tvec);
+ }
+
+ BKE_nurb_bpoint_calc_plane(nu, bp, tvec);
+ add_v3_v3(plane, tvec);
+ }
+ bp++;
+ }
+ }
}
}
@@ -1008,8 +1044,8 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
}
else {
/* we need the one selected object, if its not active */
- base = BASACT_NEW;
- ob = OBACT_NEW;
+ base = BASACT_NEW(sl);
+ ob = OBACT_NEW(sl);
if (base && ((base->flag & BASE_SELECTED) != 0)) {
/* pass */
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 1181f584313..e3ea8a51c6d 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1001,7 +1001,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
char node_border;
- if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) {
+ if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
copy_v2_v2(t->tsnap.snapPoint, loc);
t->tsnap.snapNodeBorder = node_border;
@@ -1397,22 +1397,11 @@ static bool snapNodes(
}
bool snapNodesTransform(
- TransInfo *t, const int mval[2], SnapSelect snap_select,
+ TransInfo *t, const int mval[2],
float r_loc[2], float *r_dist_px, char *r_node_border)
{
return snapNodes(
- t->settings, t->sa->spacedata.first, t->ar, mval, snap_select,
- r_loc, r_dist_px, r_node_border);
-}
-
-bool snapNodesContext(
- bContext *C, const int mval[2], SnapSelect snap_select,
- float r_loc[2], float *r_dist_px, char *r_node_border)
-{
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- return snapNodes(
- scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select,
+ t->settings, t->sa->spacedata.first, t->ar, mval, t->tsnap.modeSelect,
r_loc, r_dist_px, r_node_border);
}
@@ -1462,7 +1451,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
/* convert to frame range */
UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
- mframe = iroundf(xmouse);
+ mframe = round_fl_to_int(xmouse);
/* now find the closest sequence */
frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index cd33e18ce3e..e72bfa40480 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -51,6 +51,9 @@
#include "BKE_editmesh.h"
#include "BKE_main.h"
#include "BKE_tracking.h"
+#include "BKE_context.h"
+
+#include "DEG_depsgraph.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
@@ -101,7 +104,8 @@ typedef struct SnapObjectData_EditMesh {
struct SnapObjectContext {
Main *bmain;
Scene *scene;
- SceneLayer *scene_layer;
+ EvaluationContext eval_ctx;
+
int flag;
/* Optional: when performing screen-space projection.
@@ -131,18 +135,149 @@ struct SnapObjectContext {
};
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name Support for storing all depths, not just the first (raycast 'all')
+/** Common utilities
+* \{ */
+
+
+typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
+
+/**
+ * Walks through all objects in the scene to create the list of objets to snap.
*
- * This uses a list of #SnapObjectHitDepth structs.
+ * \param sctx: Snap context to store data.
+ * \param snap_select : from enum SnapSelect.
+ * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping.
+ */
+static void iter_snap_objects(
+ SnapObjectContext *sctx,
+ const SnapSelect snap_select,
+ Object *obedit,
+ IterSnapObjsCallback sob_callback,
+ void *data)
+{
+ Base *base_act = sctx->eval_ctx.scene_layer->basact;
+ /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
+ * which makes the loop skip it, even the derived mesh will never change
+ *
+ * To solve that problem, we do it first as an exception.
+ * */
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ sob_callback(sctx, false, base_act->object, base_act->object->obmat, data);
+ }
+
+ for (Base *base = sctx->eval_ctx.scene_layer->object_bases.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_NEW(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
+ !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) ||
+ (snap_select == SNAP_NOT_ACTIVE && base == base_act)))
+ {
+ bool use_obedit;
+ Object *obj = base->object;
+ if (obj->transflag & OB_DUPLI) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(&sctx->eval_ctx, sctx->scene, obj);
+ for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
+ use_obedit = obedit && dupli_ob->ob->data == obedit->data;
+ sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data);
+ }
+ free_object_duplilist(lb);
+ }
+
+ use_obedit = obedit && obj->data == obedit->data;
+ sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data);
+ }
+ }
+}
+
+
+/**
+ * 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;
+ */
+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])
+{
+ copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat);
+ snapdata->win_half[0] = ar->winx / 2;
+ snapdata->win_half[1] = ar->winy / 2;
+ 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);
+}
+
+
+MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
+{
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_start);
+ return dot_v3v3(dvec, ray_dir);
+}
+
+
+static bool walk_parent_bvhroot_cb(const BVHTreeAxisRange *bounds, void *userdata)
+{
+ BVHTreeRay *ray = userdata;
+ 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};
+ if (!isect_ray_aabb_v3_simple(ray->origin, ray->direction, bbmin, bbmax, &ray->radius, NULL)) {
+ ray->radius = -1;
+ }
+ return false;
+}
+
+
+static bool isect_ray_bvhroot_v3(struct BVHTree *tree, const float ray_start[3], const float ray_dir[3], float *depth)
+{
+ BVHTreeRay ray;
+ copy_v3_v3(ray.origin, ray_start);
+ copy_v3_v3(ray.direction, ray_dir);
+
+ BLI_bvhtree_walk_dfs(tree, walk_parent_bvhroot_cb, NULL, NULL, &ray);
+
+ if (ray.radius > 0) {
+ *depth = ray.radius;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Ray Cast Funcs
+* \{ */
+
+/* Store all ray-hits
+ * Support for storing all depths, not just the first (raycast 'all') */
-/* Store all ray-hits */
struct RayCastAll_Data {
void *bvhdata;
@@ -163,6 +298,7 @@ struct RayCastAll_Data {
bool retval;
};
+
static struct SnapObjectHitDepth *hit_depth_create(
const float depth, const float co[3], const float no[3], int index,
Object *ob, const float obmat[4][4], unsigned int ob_uuid)
@@ -230,57 +366,501 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
}
-/** \} */
+static bool raycastDerivedMesh(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ bool retval = false;
-/* -------------------------------------------------------------------- */
+ if (dm->getNumPolys(dm) == 0) {
+ return retval;
+ }
+
+ 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 = 0.0f;
+
+ 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_dir);
+
+ 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;
+ }
+
+ /* Test BoundBox */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ /* 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], &len_diff, NULL))
+ {
+ return retval;
+ }
+ }
+
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *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_MESH;
+ }
+
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+
+ treedata = sod->bvh_trees[2];
+
+ if (treedata) {
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ else {
+ if (treedata->vert == NULL) {
+ treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
+ }
+ if (treedata->loop == NULL) {
+ treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated);
+ }
+ if (treedata->looptri == NULL) {
+ if (sod->mpoly == NULL) {
+ sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated);
+ }
+ treedata->looptri = dm->getLoopTriArray(dm);
+ treedata->looptri_allocated = false;
+ }
+ }
+ }
+
+ if (treedata->tree == NULL) {
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+
+ if (treedata->tree == NULL) {
+ return retval;
+ }
+ }
+ }
+ else {
+ return retval;
+ }
+
+ /* 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 (len_diff == 0.0f) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Get the distance to bvhtree root */
+ if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ }
+ /* 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. */
+ madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
+ 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]);
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool raycastEditMesh(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ bool retval = false;
+ if (em->bm->totface == 0) {
+ return retval;
+ }
+
+ SnapObjectData_EditMesh *sod = NULL;
+ BVHTreeFromEditMesh *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_EDIT_MESH;
+ }
+
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[2];
+
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ 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);
+ }
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL);
+
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
+ }
+ }
+ if (treedata->tree == NULL) {
+ return retval;
+ }
+ }
+ else {
+ return retval;
+ }
+
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3], ray_start_local[3], len_diff = 0.0f;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_normal_local, ray_dir);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
+
+ /* 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;
+ }
+
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start
+ * may already been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Get the distance to bvhtree root */
+ if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ /* 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. */
+ madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
+ 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;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
-/** Common utilities
- * \{ */
/**
- * 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 use_obedit: 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_direction: Unit length direction of the ray.
- * \param depth_range: distances of clipe plane min and clip plane max;
+ * \note Duplicate args here are documented at #snapObjectsRay
*/
-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])
+static bool raycastObj(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
{
- 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;
+ bool retval = false;
+
+ if (ob->type == OB_MESH) {
+ BMEditMesh *em;
+
+ if (use_obedit) {
+ em = BKE_editmesh_from_object(ob);
+ retval = raycastEditMesh(
+ sctx,
+ ray_start, ray_dir,
+ ob, em, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ }
+ else {
+ /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
+ * still set the 'em' to NULL, since we only want the 'dm'. */
+ DerivedMesh *dm;
+ em = BKE_editmesh_from_object(ob);
+ if (em) {
+ editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
+ }
+ else {
+ dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH);
+ }
+ retval = raycastDerivedMesh(
+ sctx,
+ ray_start, ray_dir,
+ ob, dm, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ }
}
- if (mval) {
- copy_v2_v2(snapdata->mval, mval);
+
+ if (retval) {
+ if (r_ob) {
+ *r_ob = ob;
+ copy_m4_m4(r_obmat, obmat);
+ }
}
- 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);
+
+ return retval;
}
-MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
+
+struct RaycastObjUserData {
+ const float *ray_start;
+ const float *ray_dir;
+ unsigned int ob_index;
+ /* read/write args */
+ float *ray_depth;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
{
- float dvec[3];
- sub_v3_v3v3(dvec, co, ray_start);
- return dot_v3v3(dvec, ray_dir);
+ struct RaycastObjUserData *dt = data;
+ dt->ret |= raycastObj(
+ sctx,
+ dt->ray_start, dt->ray_dir,
+ ob, obmat, dt->ob_index++, is_obedit,
+ dt->ray_depth,
+ dt->r_loc, dt->r_no, dt->r_index,
+ dt->r_ob, dt->r_obmat,
+ dt->r_hit_list);
+}
+
+/**
+ * Main RayCast Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the `hit` on object surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snapdata: struct generated in `set_snapdata`.
+ * \param snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
+ * \param obj_list: List with objects to snap (created in `create_object_list`).
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Hit location.
+ * \param r_no: Hit normal (optional).
+ * \param r_index: Hit index or -1 when no valid index is found.
+ * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * \param r_ob: Hit object.
+ * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ *
+ */
+static bool raycastObjects(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ const SnapSelect snap_select, const bool use_object_edit_cage,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
+{
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
+
+ struct RaycastObjUserData data = {
+ .ray_start = ray_start,
+ .ray_dir = ray_dir,
+ .ob_index = 0,
+ .ray_depth = ray_depth,
+ .r_loc = r_loc,
+ .r_no = r_no,
+ .r_index = r_index,
+ .r_ob = r_ob,
+ .r_obmat = r_obmat,
+ .r_hit_list = r_hit_list,
+ .ret = false,
+ };
+
+ iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data);
+
+ return data.ret;
}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** Snap Nearest utilities
+ * \{ */
+
static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data)
{
const MVert *vert = data->vert + index;
@@ -489,36 +1069,20 @@ static float dist_squared_to_projected_aabb(
main_axis += 3;
}
- /* 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 */
- 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];
- 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 */
- 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;
- }
+ float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth_max < data->ray_min_dist) {
+ return FLT_MAX;
}
#endif
#undef IGNORE_BEHIND_RAY
+
+ /* if rtmin <= rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+ return 0;
+ }
+
if (data->sign[main_axis]) {
va[main_axis] = local_bvmax[main_axis];
vb[main_axis] = local_bvmin[main_axis];
@@ -559,15 +1123,12 @@ static float dist_squared_to_projected_aabb(
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);
- //sub_v2_v2v2(edge, vb2d, va2d);
- float rdist;
- short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]};
- short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]};
- float lambda = dvec[0] * edge[0] + dvec[1] * edge[1];
+ float dvec[2], edge[2], lambda, rdist;
+ sub_v2_v2v2(dvec, data->mval, va2d);
+ sub_v2_v2v2(edge, vb2d, va2d);
+ lambda = dot_v2v2(dvec, edge);
if (lambda != 0.0f) {
- lambda /= edge[0] * edge[0] + edge[1] * edge[1];
+ lambda /= len_squared_v2(edge);
if (lambda <= 0.0f) {
rdist = len_squared_v2v2(data->mval, va2d);
r_axis_closest[main_axis] = true;
@@ -604,18 +1165,6 @@ static float dist_squared_to_projected_aabb_simple(
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);
-}
-
/** \} */
@@ -1054,21 +1603,15 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
static bool snapDerivedMesh(
SnapObjectContext *sctx, SnapData *snapdata,
- Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ Object *ob, DerivedMesh *dm, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
- if (dm->getNumPolys(dm) == 0) {
- return retval;
- }
- }
- else if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -1079,38 +1622,27 @@ static bool snapDerivedMesh(
}
}
- 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 ray_normal_local[3];
+ float local_scale;
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
- 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);
/* 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;
- }
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;
- }
+
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ ray_min_dist = snapdata->depth_range[0] * local_scale;
copy_v3_v3(ray_org_local, snapdata->ray_origin);
mul_m4_v3(imat, ray_org_local);
@@ -1119,26 +1651,12 @@ static bool snapDerivedMesh(
BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
/* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, 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;
- }
- }
- else {
- /* 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;
- }
+ 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;
}
- /* 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;
}
SnapObjectData_Mesh *sod = NULL;
@@ -1155,9 +1673,6 @@ static bool snapDerivedMesh(
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;
@@ -1177,183 +1692,75 @@ static bool snapDerivedMesh(
free_bvhtree_from_mesh(treedata);
}
else {
- if (!treedata->vert_allocated) {
+ if (treedata->vert == NULL) {
treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
}
- if ((tree_index == 1) && !treedata->edge_allocated) {
- treedata->edge = DM_get_edge_array(dm, &treedata->vert_allocated);
- }
- if (tree_index == 2) {
- if (!treedata->loop_allocated) {
- treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated);
- }
- if (!treedata->looptri_allocated) {
- if (!sod->poly_allocated) {
- sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated);
- }
- treedata->looptri = DM_get_looptri_array(
- dm, treedata->vert,
- sod->mpoly, dm->getNumPolys(dm),
- treedata->loop, dm->getNumLoops(dm),
- &treedata->looptri_allocated);
- }
+ if ((tree_index == 1) && (treedata->edge == NULL)) {
+ treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated);
}
}
}
}
- 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) {
+ if (treedata->tree == NULL) {
+ switch (snapdata->snap_to) {
+ 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->tree == NULL) {
+ return retval;
}
}
- if (!treedata || !treedata->tree) {
+ else {
return retval;
}
- 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);
- }
- }
- /* 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. */
- madd_v3_v3v3fl(
- 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;
- }
- 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};
+ /* Warning: the depth_max is currently being used only in perspective view.
+ * It is not correct to limit the maximum depth for elements obtained with nearest
+ * since this limitation depends on the normal and the size of the occlusion face.
+ * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */
+ const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0];
- 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);
- }
+ 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_max_global},
+ .userdata = treedata,
+ .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no,
+ .index = -1};
- retval = true;
+ 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);
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
- }
- }
- }
- }
- }
- /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */
- else {
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
- /* Warning: the depth_max is currently being used only in perspective view.
- * It is not correct to limit the maximum depth for elements obtained with nearest
- * since this limitation depends on the normal and the size of the occlusion face.
- * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */
- const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0];
-
- 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_max_global},
- .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);
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
- retval = true;
+ 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;
}
return retval;
@@ -1361,20 +1768,14 @@ static bool snapDerivedMesh(
static bool snapEditMesh(
SnapObjectContext *sctx, SnapData *snapdata,
- Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ Object *ob, BMEditMesh *em, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
- if (em->bm->totface == 0) {
- return retval;
- }
- }
if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
return retval;
@@ -1399,13 +1800,8 @@ static bool snapEditMesh(
/* 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;
- }
SnapObjectData_EditMesh *sod = NULL;
-
BVHTreeFromEditMesh *treedata = NULL;
void **sod_p;
@@ -1419,9 +1815,6 @@ static bool snapEditMesh(
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;
@@ -1436,197 +1829,90 @@ static bool snapEditMesh(
treedata = sod->bvh_trees[tree_index];
}
- 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);
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ switch (snapdata->snap_to) {
+ 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);
+ }
+ bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6);
+ 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:
+ {
+ 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;
}
- 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 (elem_mask) {
+ MEM_freeN(elem_mask);
}
}
- if (elem_mask) {
- MEM_freeN(elem_mask);
+ if (treedata->tree == NULL) {
+ return retval;
}
}
-
- if (!treedata || !treedata->tree) {
+ else {
return retval;
}
- 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);
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_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!
- */
- 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.
- */
- 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, 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. */
- madd_v3_v3v3fl(
- 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};
+ 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};
- 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);
- }
+ 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);
- retval = true;
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
- if (r_index) {
- *r_index = hit.index;
- }
- }
- }
- }
- }
- 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);
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
- retval = true;
+ 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;
}
return retval;
@@ -1639,14 +1925,13 @@ static bool snapEditMesh(
*/
static bool snapObject(
SnapObjectContext *sctx, SnapData *snapdata,
- Object *ob, float obmat[4][4], const unsigned int ob_index,
+ Object *ob, float obmat[4][4],
bool use_obedit,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- Object **r_ob, float r_obmat[4][4],
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
bool retval = false;
@@ -1656,10 +1941,9 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, snapdata, ob, em, obmat, ob_index,
+ sctx, snapdata, ob, em, obmat,
ray_depth, dist_px,
- r_loc, r_no, r_index,
- r_hit_list);
+ r_loc, r_no);
}
else {
/* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
@@ -1667,16 +1951,15 @@ static bool snapObject(
DerivedMesh *dm;
em = BKE_editmesh_from_object(ob);
if (em) {
- editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
+ editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
}
else {
- dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, snapdata, ob, dm, obmat, ob_index,
+ sctx, snapdata, ob, dm, obmat,
ray_depth, dist_px,
- r_loc, r_no,
- r_index, r_hit_list);
+ r_loc, r_no);
dm->release(dm);
}
@@ -1721,6 +2004,34 @@ static bool snapObject(
return retval;
}
+
+struct SnapObjUserData {
+ SnapData *snapdata;
+ /* read/write args */
+ float *ray_depth;
+ float *dist_px;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ bool ret;
+};
+
+static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+{
+ struct SnapObjUserData *dt = data;
+ dt->ret |= snapObject(
+ sctx, dt->snapdata,
+ ob, obmat, is_obedit,
+ /* read/write args */
+ dt->ray_depth, dt->dist_px,
+ /* return args */
+ dt->r_loc, dt->r_no,
+ dt->r_ob, dt->r_obmat);
+}
+
+
/**
* Main Snapping Function
* ======================
@@ -1729,8 +2040,8 @@ static bool snapObject(
*
* \param sctx: Snap context to store data.
* \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 snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
*
* Read/Write Args
* ---------------
@@ -1747,89 +2058,33 @@ static bool snapObject(
* (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
- * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*
*/
static bool snapObjectsRay(
SnapObjectContext *sctx, SnapData *snapdata,
- const SnapSelect snap_select,
- const bool use_object_edit_cage,
+ const SnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- Object **r_ob, float r_obmat[4][4],
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
- bool retval = false;
-
- unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
- /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
- * which makes the loop skip it, even the derived mesh will never change
- *
- * To solve that problem, we do it first as an exception.
- * */
- Base *base_act = sctx->scene_layer->basact;
- if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base_act->object;
-
- retval |= snapObject(
- 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);
- }
-
- bool ignore_object_selected = false, ignore_object_active = false;
- switch (snap_select) {
- case SNAP_ALL:
- break;
- case SNAP_NOT_SELECTED:
- ignore_object_selected = true;
- break;
- case SNAP_NOT_ACTIVE:
- ignore_object_active = true;
- break;
- }
- for (Base *base = sctx->scene_layer->object_bases.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE_NEW(base)) &&
- (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
-
- !((ignore_object_selected && (((base->flag & BASE_SELECTED) != 0) || ((base->flag_legacy & BA_WAS_SEL)))) ||
- (ignore_object_active && base == base_act)))
- {
- Object *ob = base->object;
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
- Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
-
- retval |= snapObject(
- sctx, 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);
- }
-
- free_object_duplilist(lb);
- }
-
- bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
- Object *ob_snap = use_obedit ? obedit : ob;
+ struct SnapObjUserData data = {
+ .snapdata = snapdata,
+ .ray_depth = ray_depth,
+ .dist_px = dist_px,
+ .r_loc = r_loc,
+ .r_no = r_no,
+ .r_ob = r_ob,
+ .r_obmat = r_obmat,
+ .ret = false,
+ };
- retval |= snapObject(
- 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);
- }
- }
+ iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data);
- return retval;
+ return data.ret;
}
/** \} */
@@ -1849,7 +2104,8 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
- sctx->scene_layer = sl;
+
+ DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, sl, DAG_EVAL_VIEWPORT);
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -1924,25 +2180,17 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- 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, &snapdata,
+ return raycastObjects(
+ sctx,
+ ray_start, ray_normal,
params->snap_select, params->use_object_edit_cage,
- ray_depth, NULL,
- r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
@@ -1954,13 +2202,11 @@ bool ED_transform_snap_object_project_ray_ex(
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- const float depth_range[2] = {0.0f, FLT_MAX};
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1969,15 +2215,11 @@ 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, &snapdata,
+ bool retval = raycastObjects(
+ sctx,
+ ray_start, ray_normal,
params->snap_select, params->use_object_edit_cage,
- &ray_depth, NULL,
- NULL, NULL, NULL, NULL, NULL,
+ &ray_depth, NULL, NULL, NULL, NULL, NULL,
r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
@@ -2010,7 +2252,6 @@ static bool transform_snap_context_project_ray_impl(
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
@@ -2156,16 +2397,24 @@ 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);
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ return raycastObjects(
+ sctx,
+ ray_start, ray_normal,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, r_loc, r_no, r_index, NULL, NULL, NULL);
+ }
+ else {
+ 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, &snapdata,
- params->snap_select, params->use_object_edit_cage,
- ray_depth, dist_px,
- r_loc, r_no, r_index, NULL, NULL, NULL);
+ return snapObjectsRay(
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, dist_px, r_loc, r_no, NULL, NULL);
+ }
}
bool ED_transform_snap_object_project_view3d(
@@ -2206,7 +2455,6 @@ bool ED_transform_snap_object_project_all_view3d_ex(
return ED_transform_snap_object_project_ray_all(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);