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:
authorLukas Tönne <lukas.toenne@gmail.com>2016-06-27 11:52:10 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-06-27 11:52:10 +0300
commit73140ca2834f41ee118275fd1df0d492a554f7e8 (patch)
tree2d599421ab9c74273f55d98c2bdff54766ef23fd /source/blender/editors/transform
parent32455e230aaf22302cf4bdd5846e0a43020d75ad (diff)
parentf1253f5d2b710d4a3b3fcb4534007877a136702c (diff)
Merge branch 'master' into strand_editmode
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.c261
-rw-r--r--source/blender/editors/transform/transform.h28
-rw-r--r--source/blender/editors/transform/transform_constraints.c6
-rw-r--r--source/blender/editors/transform/transform_conversions.c72
-rw-r--r--source/blender/editors/transform/transform_generics.c76
-rw-r--r--source/blender/editors/transform/transform_ops.c5
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c1367
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1742
10 files changed, 2183 insertions, 1379 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index f3047c088a9..b7de49d8158 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
transform_ops.c
transform_orientations.c
transform_snap.c
+ transform_snap_object.c
transform.h
)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 29c152c2f6e..7671154526a 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -80,6 +80,7 @@
#include "WM_api.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -93,8 +94,6 @@
/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
// #define USE_NUM_NO_ZERO
-#define MAX_INFO_LEN 256
-
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
static void doEdgeSlide(TransInfo *t, float perc);
static void doVertSlide(TransInfo *t, float perc);
@@ -1203,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1213,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1223,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -2864,7 +2872,7 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
- calculateCenterGlobal(t);
+ calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
@@ -2910,7 +2918,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float pivot[3];
float warp_end_radius[3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const struct BendCustomData *data = t->custom.mode.data;
const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
@@ -2948,13 +2956,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
&c[0], &c[NUM_STR_REP_LEN],
WM_bool_as_string(is_clamp));
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
RAD2DEGF(values.angle), values.scale * data->warp_init_dist,
WM_bool_as_string(is_clamp));
}
@@ -3104,7 +3112,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
float value;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
copy_m3_m4(persmat, t->viewmat);
@@ -3124,11 +3132,11 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
unit_m3(smat);
@@ -3228,7 +3236,7 @@ static void initResize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -3244,32 +3252,32 @@ static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s%s %s"),
&tvec[0], t->con.text, t->proptext);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
&tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
break;
}
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -3394,7 +3402,7 @@ static void applyResize(TransInfo *t, const int mval[2])
TransData *td;
float mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
if (t->flag & T_AUTOVALUES) {
copy_v3_v3(t->values, t->auto_values);
@@ -3512,7 +3520,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
copy_v3_fl(size, t->values[0]);
@@ -3610,7 +3618,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
float vec[3];
float ratio, radius;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
ratio = t->values[0];
@@ -3629,11 +3637,11 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
@@ -3964,7 +3972,7 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3])
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
@@ -3995,15 +4003,15 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"),
RAD2DEGF(final), t->con.text, t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
applyRotationValue(t, final, t->axis);
@@ -4074,7 +4082,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float axis1[3], axis2[3];
#if 0 /* UNUSED */
@@ -4100,16 +4108,16 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %s %s %s"),
&c[0], &c[NUM_STR_REP_LEN], t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %.2f %.2f %s"),
RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
#if 0 /* UNUSED */
@@ -4145,7 +4153,12 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
r_snap[2] = r_snap[1] * 0.1f;
}
}
- else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ else if (t->spacetype == SPACE_IMAGE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.0625f;
+ r_snap[2] = 0.03125f;
+ }
+ else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = 0.0f;
r_snap[1] = 0.125f;
r_snap[2] = 0.0625f;
@@ -4206,7 +4219,7 @@ static void initTranslation(TransInfo *t)
}
}
-static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
@@ -4268,15 +4281,15 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s (%s)%s %s %s",
&tvec[0], distvec, t->con.text, t->proptext, autoik);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec,
t->con.text, t->proptext, autoik);
break;
@@ -4284,18 +4297,18 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s (%s)%s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text,
t->proptext, autoik);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
if (t->spacetype == SPACE_NODE) {
@@ -4304,11 +4317,11 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? IFACE_("right") : IFACE_("left");
- char str_km[MAX_INFO_LEN];
+ char str_km[64];
WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km);
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
str_dir, str_km, str_old);
MEM_freeN((void *)str_old);
@@ -4376,7 +4389,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float value_final[3];
if (t->flag & T_AUTOVALUES) {
@@ -4468,7 +4481,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
TransData *td = t->data;
@@ -4481,29 +4494,29 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = -distance;
/* header print for NumInput */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c);
}
else {
/* default header print */
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance);
}
if (t->proptext[0]) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", (");
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, ", (");
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, sizeof(str) - ofs, str + ofs);
}
}
- BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
+ BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" or Alt) Even Thickness %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
@@ -4563,7 +4576,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -4580,13 +4593,13 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
/* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
t->values[0] = final;
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4644,7 +4657,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4659,10 +4672,10 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4724,7 +4737,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
float ratio;
int i;
bool initial_feather = false;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4739,10 +4752,10 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %3f"), ratio);
}
/* detect if no points have feather yet */
@@ -4824,7 +4837,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4839,10 +4852,10 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4897,7 +4910,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
float vec[3], axis[3];
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
distance = t->values[0];
@@ -4914,11 +4927,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
@@ -4989,7 +5002,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float weight;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
weight = t->values[0];
@@ -5008,16 +5021,16 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5069,7 +5082,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float crease;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
crease = t->values[0];
@@ -5088,16 +5101,16 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%.3f %s"), crease, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5151,7 +5164,7 @@ static void initBoneSize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
@@ -5166,13 +5179,13 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_L
/* hmm... perhaps the y-axis values don't need to be shown? */
if (t->con.mode & CON_APPLY) {
if (t->num.idx_max == 0)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s : %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
@@ -5203,7 +5216,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
float size[3], mat[3][3];
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
// TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
/* for manipulator, center handle, the scaling can't be done relative to center */
@@ -5282,7 +5295,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -5297,10 +5310,10 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -6959,7 +6972,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
EdgeSlideData *sld = t->custom.mode.data;
@@ -6982,20 +6995,20 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7527,7 +7540,7 @@ static void doVertSlide(TransInfo *t, float perc)
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
VertSlideData *sld = t->custom.mode.data;
@@ -7550,20 +7563,20 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7607,7 +7620,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -7624,10 +7637,10 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %s"), &c[0]);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final));
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %.2f"), RAD2DEGF(final));
}
/* set roll values */
@@ -7675,7 +7688,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
TransData *td = t->data;
float time;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float fac = 0.1f;
@@ -7704,16 +7717,16 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
outputNumInput(&(t->num), c, &t->scene->unit);
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%.3f %s"), time, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -7759,7 +7772,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/*
* OPTIMIZATION:
@@ -7777,7 +7790,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
t->con.applySize(t, NULL, mat);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text);
+ BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -7906,7 +7919,7 @@ static void initSeqSlide(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
}
-static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN])
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -7918,15 +7931,15 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, UI_MAX_DRAW_STR - ofs, str + ofs);
}
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" or Alt) Expand to fit %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
@@ -7948,7 +7961,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
static void applySeqSlide(TransInfo *t, const int mval[2])
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
snapSequenceBounds(t, mval);
@@ -8127,7 +8140,7 @@ static void initTimeTranslate(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
int ofs = 0;
@@ -8166,10 +8179,10 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("DeltaX: %s"), &tvec[0]);
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -8231,7 +8244,7 @@ static void applyTimeTranslateValue(TransInfo *t)
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate translation amount from mouse movement - in 'time-grid space' */
if (t->flag & T_MODAL) {
@@ -8323,7 +8336,7 @@ static void initTimeSlide(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN])
+static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8343,7 +8356,7 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LE
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("TimeSlide: %s"), &tvec[0]);
}
static void applyTimeSlideValue(TransInfo *t, float sval)
@@ -8400,7 +8413,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
const float *range = t->custom.mode.data;
float minx = range[0];
float maxx = range[1];
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate mouse co-ordinates */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
@@ -8473,7 +8486,7 @@ static void initTimeScale(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8482,7 +8495,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
else
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleX: %s"), &tvec[0]);
}
static void applyTimeScaleValue(TransInfo *t)
@@ -8526,7 +8539,7 @@ static void applyTimeScaleValue(TransInfo *t)
static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -8558,5 +8571,3 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
-
-#undef MAX_INFO_LEN
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 7cec86d087d..b756de1ca18 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -59,6 +59,7 @@ struct wmTimer;
struct ARegion;
struct ReportList;
struct EditBone;
+struct SnapObjectContext;
/* transinfo->redraw */
typedef enum {
@@ -101,6 +102,11 @@ typedef struct TransSnap {
* where the smallest absolute value defines whats closest.
*/
float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]);
+
+ /**
+ * Re-usable snap context data.
+ */
+ struct SnapObjectContext *object_context;
} TransSnap;
typedef struct TransCon {
@@ -363,6 +369,11 @@ typedef struct TransCustomData {
unsigned int use_free : 1;
} TransCustomData;
+typedef struct TransCenterData {
+ float local[3], global[3];
+ unsigned int is_set : 1;
+} TransCenterData;
+
typedef struct TransInfo {
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
@@ -390,6 +401,9 @@ typedef struct TransInfo {
float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
+ /* Lazy initialize center data for when we need other center values.
+ * V3D_AROUND_ACTIVE + 1 (static assert checks this) */
+ TransCenterData center_cache[5];
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
@@ -578,6 +592,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
@@ -678,6 +696,7 @@ bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
+void freeSnapping(struct TransInfo *t);
void applyProject(TransInfo *t);
void applyGridAbsolute(TransInfo *t);
void applySnapping(TransInfo *t, float *vec);
@@ -736,8 +755,11 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(TransInfo *t);
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3]);
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
/* API functions for getting center points */
@@ -787,4 +809,8 @@ void projectVertSlideData(TransInfo *t, bool is_final);
/* TODO. transform_queries.c */
bool checkUseAxisMatrix(TransInfo *t);
+#define TRANSFORM_DIST_MAX_PX 1000.0f
+#define TRANSFORM_SNAP_MAX_PX 100.0f
+#define TRANSFORM_DIST_INVALID -FLT_MAX
+
#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index beeba7cf10f..13cc0c22778 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -267,9 +267,9 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
/* possible some values become nan when
* viewpoint and object are both zero */
- if (!finite(out[0])) out[0] = 0.0f;
- if (!finite(out[1])) out[1] = 0.0f;
- if (!finite(out[2])) out[2] = 0.0f;
+ if (!isfinite(out[0])) out[0] = 0.0f;
+ if (!isfinite(out[1])) out[1] = 0.0f;
+ if (!isfinite(out[2])) out[2] = 0.0f;
}
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index a743a337111..6d0651e174c 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -821,6 +821,7 @@ static void pose_grab_with_ik_clear(Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
+ bool need_dependency_update = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -835,6 +836,7 @@ static void pose_grab_with_ik_clear(Object *ob)
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
/* iTaSC needs clear for removed constraints */
+ need_dependency_update = true;
BIK_clear_data(ob->pose);
BLI_remlink(&pchan->constraints, con);
@@ -850,10 +852,10 @@ static void pose_grab_with_ik_clear(Object *ob)
}
#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy())
+ if (!DEG_depsgraph_use_legacy() && need_dependency_update)
#endif
{
- /* TODO(sergey): Consuder doing partial update only. */
+ /* TODO(sergey): Consider doing partial update only. */
DAG_relations_tag_update(G.main);
}
}
@@ -2879,6 +2881,20 @@ void flushTransSeq(TransInfo *t)
BKE_sequence_calc(t->scene, seq);
}
}
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
+ a < t->total;
+ a++, td++, td2d++, seq_prev = seq)
+ {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
}
/* need to do the overlap check in a new loop otherwise adjacent strips
@@ -5123,44 +5139,47 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
break;
}
- seq_prev = seq;
}
if (overlap) {
- bool has_effect = false;
+ bool has_effect_root = false, has_effect_any = false;
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect = true;
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
}
else {
- /* Tag seq with a non zero value, used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- seq->tmp = (void *)1;
+ /* Tag seq with a non zero value,
+ * used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
}
}
+
}
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
}
}
@@ -5192,11 +5211,10 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
BKE_sequence_base_shuffle_time(seqbasep, t->scene);
}
- if (has_effect) {
+ if (has_effect_any) {
/* update effects strips based on strips just moved in time */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5204,13 +5222,14 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
}
}
+ }
+ if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
if (BKE_sequence_test_overlap(seqbasep, seq)) {
BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
@@ -6077,6 +6096,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
if (t->flag & T_MIRROR) {
TransData *td;
@@ -6100,8 +6120,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
EDBM_automerge(t->scene, t->obedit, true, hflag);
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_select_flush(em);
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
}
}
}
@@ -7797,7 +7819,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
if (pcp->bez.f2 & SELECT) {
td += 3;
@@ -8025,7 +8047,9 @@ static void createTransGPencil(bContext *C, TransInfo *t)
copy_m3_m3(td->mtx, mtx);
unit_m3(td->axismtx); // XXX?
}
-
+ /* Triangulation must be calculated again, so save the stroke for recalc function */
+ td->extra = gps;
+
td++;
tail++;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 44c4f2e482b..ebb427fed67 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -976,6 +976,16 @@ static void recalcData_sequencer(TransInfo *t)
flushTransSeq(t);
}
+/* force recalculation of triangles during transformation */
+static void recalcData_gpencil_strokes(TransInfo *t)
+ {
+ TransData *td = t->data;
+ for (int i = 0; i < t->total; i++, td++) {
+ bGPDstroke *gps = td->extra;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+}
+
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -990,7 +1000,8 @@ void recalcData(TransInfo *t)
flushTransPaintCurve(t);
}
else if (t->options & CTX_GPENCIL_STROKES) {
- /* pass? */
+ /* set recalc triangle cache flag */
+ recalcData_gpencil_strokes(t);
}
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
@@ -1509,6 +1520,8 @@ void postTrans(bContext *C, TransInfo *t)
if (t->mouse.data) {
MEM_freeN(t->mouse.data);
}
+
+ freeSnapping(t);
}
void applyTransObjects(TransInfo *t)
@@ -1604,16 +1617,18 @@ void calculateCenter2D(TransInfo *t)
}
}
-void calculateCenterGlobal(TransInfo *t)
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ mul_v3_m4v3(r_center_global, ob->obmat, center_local);
}
else {
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(r_center_global, center_local);
}
}
@@ -1788,43 +1803,55 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
return ok;
}
-
-void calculateCenter(TransInfo *t)
+static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
{
- switch (t->around) {
+ switch (around) {
case V3D_AROUND_CENTER_BOUNDS:
- calculateCenterBound(t, t->center);
+ calculateCenterBound(t, r_center);
break;
case V3D_AROUND_CENTER_MEAN:
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_CURSOR:
if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
- calculateCenterCursor2D(t, t->center);
+ calculateCenterCursor2D(t, r_center);
else if (t->spacetype == SPACE_IPO)
- calculateCenterCursorGraph2D(t, t->center);
+ calculateCenterCursorGraph2D(t, r_center);
else
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, r_center);
break;
case V3D_AROUND_LOCAL_ORIGINS:
/* Individual element center uses median center for helpline and such */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_ACTIVE:
{
- if (calculateCenterActive(t, false, t->center)) {
+ if (calculateCenterActive(t, false, r_center)) {
/* pass */
}
else {
/* fallback */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
}
break;
}
}
+}
+
+void calculateCenter(TransInfo *t)
+{
+ calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenterGlobal(t, t->center, t->center_global);
+
+ /* avoid calculating again */
+ {
+ TransCenterData *cd = &t->center_cache[t->around];
+ copy_v3_v3(cd->local, t->center);
+ copy_v3_v3(cd->global, t->center_global);
+ cd->is_set = true;
+ }
calculateCenter2D(t);
- calculateCenterGlobal(t);
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
@@ -1878,6 +1905,23 @@ void calculateCenter(TransInfo *t)
}
}
+BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
+
+/**
+ * Lazy initialize transform center data, when we need to access center values from other types.
+ */
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
+{
+ BLI_assert(around <= V3D_AROUND_ACTIVE);
+ TransCenterData *cd = &t->center_cache[around];
+ if (cd->is_set == false) {
+ calculateCenter_FromAround(t, around, cd->local);
+ calculateCenterGlobal(t, cd->local, cd->global);
+ cd->is_set = true;
+ }
+ return cd;
+}
+
void calculatePropRatio(TransInfo *t)
{
TransData *td = t->data;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 5d49d1d9315..6e399d9fde3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
@@ -686,7 +687,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Tilt";
- /* optionals -
+ /* optional -
* "Tilt selected vertices"
* "Specify an extra axis rotation for selected vertices of 3D curve" */
ot->description = "Tilt selected control vertices of 3D curve";
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 5c9b250b274..7ac2daa5fa7 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -636,7 +636,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_face_calc_plane(efa, vec);
+ BM_face_calc_tangent_auto(efa, vec);
add_v3_v3(normal, efa->no);
add_v3_v3(plane, vec);
}
@@ -690,7 +690,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
}
else {
- BM_vert_tri_calc_plane(v_tri, plane);
+ BM_vert_tri_calc_tangent_edge(v_tri, plane);
}
}
else {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index bb9120c337b..0bb64315845 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -36,8 +36,6 @@
#include "PIL_time.h"
-#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h" /* Temporary, for snapping to other unselected meshes */
@@ -61,17 +59,16 @@
#include "BKE_editmesh.h"
#include "BKE_sequencer.h"
#include "BKE_main.h"
-#include "BKE_tracking.h"
#include "RNA_access.h"
#include "WM_types.h"
-#include "ED_armature.h"
#include "ED_image.h"
#include "ED_node.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
+#include "ED_transform_snap_object_context.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -83,10 +80,6 @@
/* this should be passed as an arg for use in snap functions */
#undef BASACT
-#define TRANSFORM_DIST_MAX_PX 1000.0f
-#define TRANSFORM_SNAP_MAX_PX 100.0f
-#define TRANSFORM_DIST_INVALID -FLT_MAX
-
/* use half of flt-max so we can scale up without an exception */
/********************* PROTOTYPES ***********************/
@@ -331,8 +324,8 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (snapObjectsTransform(
- t, mval_fl, t->tsnap.modeSelect,
- loc, no, &dist_px))
+ t, mval_fl, &dist_px,
+ loc, no))
{
// if (t->flag & (T_EDIT|T_POSE)) {
// mul_m4_v3(imat, loc);
@@ -493,6 +486,35 @@ bool validSnappingNormal(TransInfo *t)
return false;
}
+static bool bm_edge_is_snap_target(BMEdge *e, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT | BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT | BM_ELEM_HIDDEN)) {
+ return false;
+ }
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
+ return false;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return true;
+}
+
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -531,10 +553,10 @@ static void initSnappingMode(TransInfo *t)
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
- t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
}
}
/* Particles edit mode*/
@@ -573,6 +595,21 @@ static void initSnappingMode(TransInfo *t)
/* Always grid outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->tsnap.object_context == NULL) {
+ t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
+ G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ t->ar, t->view);
+
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ bm_edge_is_snap_target,
+ bm_face_is_snap_target,
+ SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
+ }
+ }
}
void initSnapping(TransInfo *t, wmOperator *op)
@@ -636,6 +673,14 @@ void initSnapping(TransInfo *t, wmOperator *op)
initSnappingMode(t);
}
+void freeSnapping(TransInfo *t)
+{
+ if (t->tsnap.object_context) {
+ ED_transform_snap_object_context_destroy(t->tsnap.object_context);
+ t->tsnap.object_context = NULL;
+ }
+}
+
static void setSnappingCallback(TransInfo *t)
{
t->tsnap.calcSnap = CalcSnapGeometry;
@@ -797,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
vec[1] = point[1] - t->tsnap.snapTarget[1];
}
else {
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ zero_v3(point); /* no good answer here... */
+ }
+ }
+ }
+
sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
}
}
@@ -918,92 +971,16 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
mval[1] = t->mval[1];
if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
- ListBase depth_peels;
- DepthPeel *p1, *p2;
- const float *last_p = NULL;
- float max_dist = FLT_MAX;
- float p[3] = {0.0f, 0.0f, 0.0f};
-
- BLI_listbase_clear(&depth_peels);
-
- peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels);
-
-// if (LAST_SNAP_POINT_VALID)
-// {
-// last_p = LAST_SNAP_POINT;
-// }
-// else
- {
- last_p = t->tsnap.snapPoint;
- }
-
-
- for (p1 = depth_peels.first; p1; p1 = p1->next) {
- if (p1->flag == 0) {
- float vec[3];
- float new_dist;
-
- p2 = NULL;
- p1->flag = 1;
-
- /* if peeling objects, take the first and last from each object */
- if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) {
- DepthPeel *peel;
- for (peel = p1->next; peel; peel = peel->next) {
- if (peel->ob == p1->ob) {
- peel->flag = 1;
- p2 = peel;
- }
- }
- }
- /* otherwise, pair first with second and so on */
- else {
- for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) {
- /* nothing to do here */
- }
- }
-
- if (p2) {
- p2->flag = 1;
-
- add_v3_v3v3(vec, p1->p, p2->p);
- mul_v3_fl(vec, 0.5f);
- }
- else {
- copy_v3_v3(vec, p1->p);
- }
-
- if (last_p == NULL) {
- copy_v3_v3(p, vec);
- max_dist = 0;
- break;
- }
-
- new_dist = len_squared_v3v3(last_p, vec);
-
- if (new_dist < max_dist) {
- copy_v3_v3(p, vec);
- max_dist = new_dist;
- }
- }
- }
-
- if (max_dist != FLT_MAX) {
- copy_v3_v3(loc, p);
- /* XXX, is there a correct normal in this case ???, for now just z up */
- no[0] = 0.0;
- no[1] = 0.0;
- no[2] = 1.0;
- found = true;
- }
-
- BLI_freelistN(&depth_peels);
+ found = peelObjectsTransform(
+ t, mval,
+ (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
+ loc, no, NULL);
}
else {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
- t, mval, t->tsnap.modeSelect,
- loc, no, &dist_px);
+ t, mval, &dist_px,
+ loc, no);
}
if (found == true) {
@@ -1237,1142 +1214,110 @@ static void TargetSnapClosest(TransInfo *t)
}
}
-static bool snapEdge(
- ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
- int result;
- bool retval = false;
-
- copy_v3_v3(ray_end, ray_normal_local);
- mul_v3_fl(ray_end, 2000);
- add_v3_v3v3(ray_end, ray_start_local, ray_end);
-
- result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
-
- if (result) {
- float edge_loc[3], vec[3];
- float mul;
-
- /* check for behind ray_start */
- sub_v3_v3v3(dvec, intersect, ray_start_local);
-
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
-
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
-
- if (mul > 1) {
- mul = 1;
- copy_v3_v3(intersect, v1co);
- }
- else if (mul < 0) {
- mul = 0;
- copy_v3_v3(intersect, v2co);
- }
-
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
-
- copy_v3_v3(location, intersect);
-
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
-
- /* 10% threshold if edge is closer but a bit further
- * this takes care of series of connected edges a bit slanted w.r.t the viewport
- * otherwise, it would stick to the verts of the closest edge and not slide along merrily
- * */
- if (new_dist <= *r_dist_px && new_depth < *ray_depth * 1.001f) {
- float n1[3], n2[3];
-
- *ray_depth = new_depth;
- retval = true;
-
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
-
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
-
- if (r_no) {
- normal_short_to_float_v3(n1, v1no);
- normal_short_to_float_v3(n2, v2no);
- interp_v3_v3v3(r_no, n2, n1, mul);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- copy_v3_v3(r_loc, location);
-
- *r_dist_px = new_dist;
- }
- }
- }
-
- return retval;
-}
-
-static bool snapVertex(
- ARegion *ar, const float vco[3], const short vno[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- bool retval = false;
- float dvec[3];
-
- sub_v3_v3v3(dvec, vco, ray_start_local);
-
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
-
- copy_v3_v3(location, vco);
-
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
-
-
- if (new_dist <= *r_dist_px && new_depth < *ray_depth) {
- *ray_depth = new_depth;
- retval = true;
-
- copy_v3_v3(r_loc, location);
-
- if (r_no) {
- normal_short_to_float_v3(r_no, vno);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- *r_dist_px = new_dist;
- }
- }
-
- return retval;
-}
-
-static bool snapArmature(
- ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- if (arm->edbo) {
- EditBone *eBone;
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->layer & arm->layer) {
- /* skip hidden or moving (selected) bones */
- if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- }
- }
- }
- }
- }
- else if (ob->pose && ob->pose->chanbase.first) {
- bPoseChannel *pchan;
- Bone *bone;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- /* skip hidden bones */
- if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
- const float *head_vec = pchan->pose_head;
- const float *tail_vec = pchan->pose_tail;
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- }
- }
- }
- }
-
- return retval;
-}
-
-static bool snapCurve(
- ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
- int u;
-
- Nurb *nu;
-
- /* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
- for (u = 0; u < nu->pntsu; u++) {
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- if (ob->mode == OB_MODE_EDIT) {
- if (nu->bezt) {
- /* don't snap to selected (moving) or hidden */
- if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
- break;
- }
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
- if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- else {
- /* don't snap to selected (moving) or hidden */
- if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
- break;
- }
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- else {
- /* curve is not visible outside editmode if nurb length less than two */
- if (nu->pntsu > 1) {
- if (nu->bezt) {
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- else {
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- }
- break;
- }
- default:
- break;
- }
- }
- }
- return retval;
-}
-
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
-{
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+bool snapObjectsTransform(
+ TransInfo *t, const float mval[2],
+ float *dist_px,
+ float r_loc[3], float r_no[3])
+{
+ return ED_transform_snap_object_project_view3d_ex(
+ t->tsnap.object_context,
+ t->scene->toolsettings->snap_mode,
+ &(const struct SnapObjectParams){
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ mval, dist_px, NULL,
+ r_loc, r_no, NULL);
}
-static bool snapDerivedMesh(
- ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float mval[2], const short snap_to, bool do_bb,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
-{
- bool retval = false;
- int totvert = dm->getNumVerts(dm);
-
- if (totvert > 0) {
- const bool do_ray_start_correction = (
- ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
- (ar && !((RegionView3D *)ar->regiondata)->is_persp));
- bool need_ray_start_correction_init = do_ray_start_correction;
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
-
- BVHTreeFromMesh treedata = {0};
-
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- /* local scale in normal direction */
- local_scale = normalize_v3(ray_normal_local);
- local_depth = *ray_depth;
- if (local_depth != BVH_RAYCAST_DIST_MAX) {
- local_depth *= local_scale;
- }
-
- if (do_bb) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (bb) {
- BoundBox bb_temp;
-
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
- * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
- bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
-
- /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'r_dist_px'),
- * scale up so we can snap against verts & edges on the boundbox, see T46816. */
- if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
- BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
- bb = &bb_temp;
- }
-
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
+/******************** PEELING *********************************/
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
- }
- need_ray_start_correction_init = false;
+bool peelObjectsSnapContext(
+ SnapObjectContext *sctx,
+ const float mval[2],
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_thickness)
+{
+ ListBase depths_peel = {0};
+ ED_transform_snap_object_project_all_view3d_ex(
+ sctx,
+ params,
+ mval, -1.0f, false,
+ &depths_peel);
+
+ if (!BLI_listbase_is_empty(&depths_peel)) {
+ /* At the moment we only use the hits of the first object */
+ struct SnapObjectHitDepth *hit_min = depths_peel.first;
+ for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) {
+ if (iter->depth < hit_min->depth) {
+ hit_min = iter;
}
}
+ struct SnapObjectHitDepth *hit_max = NULL;
- treedata.em_evil = em;
- treedata.em_evil_all = false;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- bvhtree_from_mesh_looptri(&treedata, dm, 0.0f, 4, 6);
- break;
- case SCE_SNAP_MODE_VERTEX:
- bvhtree_from_mesh_verts(&treedata, dm, 0.0f, 2, 6);
- break;
- }
-
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
-
- if (treedata.tree != NULL) {
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata.tree, ray_start_local, &nearest, treedata.nearest_callback, &treedata);
- if (nearest.index != -1) {
- len_diff = sqrtf(nearest.dist_sq);
+ if (use_peel_object) {
+ /* if peeling objects, take the first and last from each object */
+ hit_max = hit_min;
+ for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
+ if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) {
+ hit_max = iter;
}
}
}
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
else {
- len_diff = 0.0f;
- }
-
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- BVHTreeRayHit hit;
-
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata.tree &&
- BLI_bvhtree_ray_cast(treedata.tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata.raycast_callback, &treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
- copy_v3_v3(r_no, hit.no);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
-
- retval = true;
-
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata.looptri[hit.index]);
- }
- }
- }
- break;
- }
- case SCE_SNAP_MODE_VERTEX:
- {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata.tree &&
- BLI_bvhtree_find_nearest_to_ray(
- treedata.tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
- {
- const MVert *v = &treedata.vert[nearest.index];
- retval = snapVertex(
- ar, v->co, v->no, obmat, timat, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- break;
- }
- case SCE_SNAP_MODE_EDGE:
- {
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
- const int *index_array = NULL;
- int index = 0;
- int i;
-
- if (em != NULL) {
- index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
- }
-
- for (i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- bool test = true;
-
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- }
- else {
- index = i;
- }
-
- if (index == ORIGINDEX_NONE) {
- test = false;
- }
- else {
- BMEdge *eed = BM_edge_at_index(em->bm, index);
-
- if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
- {
- test = false;
- }
- }
- }
-
- if (test) {
- retval |= snapEdge(
- ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat,
- mval, ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- }
-
- break;
- }
- }
-
- free_bvhtree_from_mesh(&treedata);
- }
-
- return retval;
-}
-
-/* may extend later (for now just snaps to empty center) */
-static bool snapEmpty(
- ARegion *ar, Object *ob, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
-
- if (ob->transflag & OB_DUPLI) {
- return retval;
- }
- /* for now only vertex supported */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- const float zero_co[3] = {0.0f};
- retval |= snapVertex(
- ar, zero_co, NULL, obmat, NULL, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL, r_dist_px);
- break;
- }
- default:
- break;
- }
-
- return retval;
-}
-
-static bool snapCamera(
- ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
- bool retval = false;
- MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
- MovieTracking *tracking;
- float ray_start_local[3], ray_normal_local[3];
-
- if (clip == NULL) {
- return retval;
- }
- if (object->transflag & OB_DUPLI) {
- return retval;
- }
-
- tracking = &clip->tracking;
-
- BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
-
- invert_m4_m4(orig_camera_imat, orig_camera_mat);
- invert_m4_m4(imat, obmat);
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- MovieTrackingObject *tracking_object;
-
- for (tracking_object = tracking->objects.first;
- tracking_object;
- tracking_object = tracking_object->next)
- {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- MovieTrackingTrack *track;
- float reconstructed_camera_mat[4][4],
- reconstructed_camera_imat[4][4];
- float (*vertex_obmat)[4];
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
- CFRA, reconstructed_camera_mat);
-
- invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
- }
-
- for (track = tracksbase->first; track; track = track->next) {
- float bundle_pos[3];
-
- if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
- continue;
- }
-
- copy_v3_v3(bundle_pos, track->bundle_pos);
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_m4_v3(orig_camera_imat, ray_start_local);
- mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
- vertex_obmat = orig_camera_mat;
+ /* otherwise, pair first with second and so on */
+ for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
+ if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) {
+ if (hit_max == NULL) {
+ hit_max = iter;
}
- else {
- mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
- vertex_obmat = obmat;
+ else if (iter->depth < hit_max->depth) {
+ hit_max = iter;
}
-
- retval |= snapVertex(
- ar, bundle_pos, NULL, vertex_obmat, NULL, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL, r_dist_px);
}
}
-
- break;
- }
- default:
- break;
- }
-
- return retval;
-}
-
-static bool snapObject(
- Scene *scene, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit,
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- bool retval = false;
-
- if (ob->type == OB_MESH) {
- BMEditMesh *em;
- DerivedMesh *dm;
- bool do_bb = true;
-
- if (use_obedit) {
- em = BKE_editmesh_from_object(ob);
- dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
- do_bb = false;
- }
- else {
- /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
- * still set the 'em' to NULL, since we only want the 'dm'. */
- em = BKE_editmesh_from_object(ob);
- if (em) {
- editbmesh_get_derived_cage_and_final(scene, ob, em, CD_MASK_BAREMESH, &dm);
- }
- else {
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ /* in this case has only one hit. treat as raycast */
+ if (hit_max == NULL) {
+ hit_max = hit_min;
}
- em = NULL;
}
-
- retval = snapDerivedMesh(
- ar, ob, dm, em, obmat, mval, snap_to, do_bb,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index);
-
- dm->release(dm);
- }
- else if (ob->type == OB_ARMATURE) {
- retval = snapArmature(
- ar, ob, ob->data, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_CURVE) {
- retval = snapCurve(
- ar, ob, ob->data, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_EMPTY) {
- retval = snapEmpty(
- ar, ob, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_CAMERA) {
- retval = snapCamera(
- ar, scene, ob, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
-
- if (retval) {
- if (r_ob) {
- *r_ob = ob;
- copy_m4_m4(r_obmat, obmat);
- }
- }
- return retval;
-}
-
-static bool snapObjectsRay(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- Base *base;
- bool retval = false;
-
- if (snap_select == SNAP_ALL && obedit) {
- Object *ob = obedit;
-
- retval |= snapObject(
- scene, ar, ob, ob->obmat, true,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- /* 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;
- if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base->object;
- retval |= snapObject(
- scene, ar, ob, ob->obmat, false,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- for (base = FIRSTBASE; base != NULL; base = base->next) {
- if ((BASE_VISIBLE_BGMODE(v3d, scene, base)) &&
- (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
-
- ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
- {
- Object *ob = base->object;
- Object *ob_snap = ob;
- bool use_obedit = false;
-
- /* for linked objects, use the same object but a different matrix */
- if (obedit && ob->data == obedit->data) {
- use_obedit = true;
- ob_snap = obedit;
- }
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
- Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
-
- retval |= snapObject(
- scene, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- free_object_duplilist(lb);
- }
+ mid_v3_v3v3(r_loc, hit_min->co, hit_max->co);
- retval |= snapObject(
- scene, ar, ob_snap, ob->obmat, use_obedit,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
+ if (r_thickness) {
+ *r_thickness = hit_max->depth - hit_min->depth;
}
- }
-
- return retval;
-}
-static bool snapObjects(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
-{
- float ray_start[3], ray_normal[3], ray_orgigin[3];
- if (!ED_view3d_win_to_ray_ex(ar, v3d, mval, ray_orgigin, ray_normal, ray_start, true)) {
- return false;
- }
+ /* XXX, is there a correct normal in this case ???, for now just z up */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
- return snapObjectsRay(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_start, ray_normal, ray_orgigin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, NULL, NULL);
-}
-
-bool snapObjectsTransform(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- float ray_dist = BVH_RAYCAST_DIST_MAX;
- Object *obedit = NULL;
- Base *base_act = NULL;
-
- if (t->flag & T_EDIT) {
- obedit = t->obedit;
- }
-
- if ((t->options & CTX_GPENCIL_STROKES) == 0) {
- base_act = t->scene->basact;
+ BLI_freelistN(&depths_peel);
+ return true;
}
-
- return snapObjects(
- t->scene, t->view, t->ar, base_act, obedit,
- mval, snap_select, t->scene->toolsettings->snap_mode,
- &ray_dist,
- r_loc, r_no, r_dist_px, NULL);
-}
-
-bool snapObjectsContext(
- bContext *C, const float mval[2], SnapSelect snap_select,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
- float ray_dist = BVH_RAYCAST_DIST_MAX;
-
- return snapObjects(
- scene, v3d, ar, scene->basact, obedit,
- mval, snap_select, scene->toolsettings->snap_mode,
- &ray_dist,
- r_loc, r_no, r_dist_px, NULL);
-}
-
-bool snapObjectsEx(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- return snapObjects(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_depth,
- r_loc, r_no, r_dist_px, NULL);
-}
-bool snapObjectsRayEx(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- return snapObjectsRay(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_start, ray_normal, ray_start, ray_depth,
- r_loc, r_no, r_dist_px, r_index,
- r_ob, r_obmat);
-}
-
-/******************** PEELING *********************************/
-
-
-static int cmpPeel(const void *arg1, const void *arg2)
-{
- const DepthPeel *p1 = arg1;
- const DepthPeel *p2 = arg2;
- int val = 0;
-
- if (p1->depth < p2->depth) {
- val = -1;
- }
- else if (p1->depth > p2->depth) {
- val = 1;
- }
-
- return val;
-}
-
-static void removeDoublesPeel(ListBase *depth_peels)
-{
- DepthPeel *peel;
-
- for (peel = depth_peels->first; peel; peel = peel->next) {
- DepthPeel *next_peel = peel->next;
-
- if (next_peel && fabsf(peel->depth - next_peel->depth) < 0.0015f) {
- peel->next = next_peel->next;
-
- if (next_peel->next) {
- next_peel->next->prev = peel;
- }
-
- MEM_freeN(next_peel);
- }
- }
-}
-
-static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
-{
- DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
-
- peel->depth = depth;
- peel->ob = ob;
- copy_v3_v3(peel->p, p);
- copy_v3_v3(peel->no, no);
-
- BLI_addtail(depth_peels, peel);
-
- peel->flag = 0;
-}
-
-struct PeelRayCast_Data {
- BVHTreeFromMesh bvhdata;
-
- /* internal vars for adding peel */
- Object *ob;
- const float (*obmat)[4];
- const float (*timat)[3];
-
- const float *ray_start; /* globalspace */
-
- const MLoopTri *looptri;
- const float (*polynors)[3]; /* optional, can be NULL */
-
- /* output list */
- ListBase *depth_peels;
-};
-
-static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
-{
- struct PeelRayCast_Data *data = userdata;
-
- data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
-
- if (hit->index != -1) {
- /* get all values in worldspace */
- float location[3], normal[3];
- float depth;
-
- /* worldspace location */
- mul_v3_m4v3(location, (float (*)[4])data->obmat, hit->co);
- depth = len_v3v3(location, data->ray_start);
-
- /* worldspace normal */
- copy_v3_v3(normal, data->polynors ? data->polynors[data->looptri[hit->index].poly] : hit->no);
- mul_m3_v3((float (*)[3])data->timat, normal);
- normalize_v3(normal);
-
- addDepthPeel(data->depth_peels, depth, location, normal, data->ob);
- }
-}
-
-static bool peelDerivedMesh(
- Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
- ListBase *depth_peels)
-{
- bool retval = false;
- int totvert = dm->getNumVerts(dm);
-
- if (totvert > 0) {
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- const int looptri_num = dm->getNumLoopTri(dm);
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- bool test = true;
-
- invert_m4_m4(imat, obmat);
-
- transpose_m3_m4(timat, imat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- /* If number of vert is more than an arbitrary limit,
- * test against boundbox first
- * */
- if (looptri_num > 16) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (bb) {
- BoundBox bb_temp;
-
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
- * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
- bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
-
- test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL);
- }
- }
-
- if (test == true) {
- struct PeelRayCast_Data data;
-
- data.bvhdata.em_evil = em;
- data.bvhdata.em_evil_all = false;
- bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6);
-
- if (data.bvhdata.tree != NULL) {
- data.ob = ob;
- data.obmat = (const float (*)[4])obmat;
- data.timat = (const float (*)[3])timat;
- data.ray_start = ray_start;
- data.looptri = looptri;
- data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
- data.depth_peels = depth_peels;
-
- BLI_bvhtree_ray_cast_all(data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f,
- peelRayCast_cb, &data);
- }
-
- free_bvhtree_from_mesh(&data.bvhdata);
- }
- }
-
- return retval;
-}
-
-static bool peelObjects(
- Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
- const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
-{
- Base *base;
- bool retval = false;
- float ray_start[3], ray_normal[3];
-
- if (ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal, true) == false) {
- return false;
- }
-
- for (base = scene->base.first; base != NULL; base = base->next) {
- if (BASE_SELECTABLE(v3d, base)) {
- Object *ob = base->object;
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- Object *dob = dupli_ob->ob;
-
- if (dob->type == OB_MESH) {
- BMEditMesh *em;
- DerivedMesh *dm = NULL;
- bool val;
-
- if (dob != obedit) {
- dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- }
- else {
- em = BKE_editmesh_from_object(dob);
- dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- }
-
- retval = retval || val;
-
- dm->release(dm);
- }
- }
-
- free_object_duplilist(lb);
- }
-
- if (ob->type == OB_MESH) {
- bool val = false;
-
- if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) {
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- dm->release(dm);
- }
- else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) {
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- dm->release(dm);
- }
-
- retval = retval || val;
-
- }
- }
- }
-
- BLI_listbase_sort(r_depth_peels, cmpPeel);
- removeDoublesPeel(r_depth_peels);
-
- return retval;
-}
-
-bool peelObjectsTransForm(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
-{
- return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels);
+ return false;
}
-bool peelObjectsContext(
- bContext *C, const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
-{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
-
- return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels);
+bool peelObjectsTransform(
+ TransInfo *t,
+ const float mval[2],
+ const bool use_peel_object,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_thickness)
+{
+ return peelObjectsSnapContext(
+ t->tsnap.object_context,
+ mval,
+ &(const struct SnapObjectParams){
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ use_peel_object,
+ r_loc, r_no, r_thickness);
}
/******************** NODES ***********************************/
@@ -2586,11 +1531,21 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
/* absolute snapping on grid based on global center */
if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) {
+ const float *center_global = t->center_global;
+
+ /* use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ if (t->around == V3D_AROUND_CURSOR) {
+ const TransCenterData *cd = transformCenter_from_type(t, V3D_AROUND_CENTER_MEAN);
+ center_global = cd->global;
+ }
+
for (i = 0; i <= max_index; i++) {
/* do not let unconstrained axis jump to absolute grid increments */
if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
const float iter_fac = fac[action] * asp[i];
- val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
new file mode 100644
index 00000000000..28ad1d93215
--- /dev/null
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -0,0 +1,1742 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_snap_object.c
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_anim.h" /* for duplis */
+#include "BKE_editmesh.h"
+#include "BKE_main.h"
+#include "BKE_tracking.h"
+
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+#include "ED_armature.h"
+
+#include "transform.h"
+
+typedef struct SnapObjectData {
+ enum {
+ SNAP_MESH = 1,
+ SNAP_EDIT_MESH,
+ } type;
+} SnapObjectData;
+
+typedef struct SnapObjectData_Mesh {
+ SnapObjectData sd;
+ BVHTreeFromMesh *bvh_trees[2];
+
+} SnapObjectData_Mesh;
+
+typedef struct SnapObjectData_EditMesh {
+ SnapObjectData sd;
+ BVHTreeFromEditMesh *bvh_trees[2];
+
+} SnapObjectData_EditMesh;
+
+struct SnapObjectContext {
+ Main *bmain;
+ Scene *scene;
+ int flag;
+
+ /* Optional: when performing screen-space projection.
+ * otherwise this doesn't take viewport into account. */
+ bool use_v3d;
+ struct {
+ struct View3D *v3d;
+ struct ARegion *ar;
+ } v3d_data;
+
+
+ /* Object -> SnapObjectData map */
+ struct {
+ GHash *object_map;
+ MemArena *mem_arena;
+ } cache;
+
+ /* Filter data, returns true to check this value */
+ struct {
+ struct {
+ bool (*test_vert_fn)(BMVert *, void *user_data);
+ bool (*test_edge_fn)(BMEdge *, void *user_data);
+ bool (*test_face_fn)(BMFace *, void *user_data);
+ void *user_data;
+ } edit_mesh;
+ } callbacks;
+
+};
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Support for storing all depths, not just the first (raycast 'all')
+ *
+ * This uses a list of #SnapObjectHitDepth structs.
+ *
+ * \{ */
+
+/* Store all ray-hits */
+struct RayCastAll_Data {
+ void *bvhdata;
+
+ /* internal vars for adding depths */
+ BVHTree_RayCastCallback raycast_callback;
+
+ const float(*obmat)[4];
+ const float(*timat)[3];
+
+ float len_diff;
+ float local_scale;
+
+ Object *ob;
+ unsigned int ob_uuid;
+
+ /* DerivedMesh only */
+ DerivedMesh *dm;
+ const struct MLoopTri *dm_looptri;
+
+ /* output data */
+ ListBase *hit_list;
+ 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)
+{
+ struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
+
+ hit->depth = depth;
+ copy_v3_v3(hit->co, co);
+ copy_v3_v3(hit->no, no);
+ hit->index = index;
+
+ hit->ob = ob;
+ copy_m4_m4(hit->obmat, (float(*)[4])obmat);
+ hit->ob_uuid = ob_uuid;
+
+ return hit;
+}
+
+static int hit_depth_cmp(const void *arg1, const void *arg2)
+{
+ const struct SnapObjectHitDepth *h1 = arg1;
+ const struct SnapObjectHitDepth *h2 = arg2;
+ int val = 0;
+
+ if (h1->depth < h2->depth) {
+ val = -1;
+ }
+ else if (h1->depth > h2->depth) {
+ val = 1;
+ }
+
+ return val;
+}
+
+static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ struct RayCastAll_Data *data = userdata;
+ data->raycast_callback(data->bvhdata, index, ray, hit);
+ if (hit->index != -1) {
+ /* get all values in worldspace */
+ float location[3], normal[3];
+ float depth;
+
+ /* worldspace location */
+ mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
+ depth = (hit->dist + data->len_diff) / data->local_scale;
+
+ /* worldspace normal */
+ copy_v3_v3(normal, hit->no);
+ mul_m3_v3((float(*)[3])data->timat, normal);
+ normalize_v3(normal);
+
+ /* currently unused, and causes issues when looptri's haven't been calculated.
+ * since theres some overhead in ensuring this data is valid, it may need to be optional. */
+#if 0
+ if (data->dm) {
+ hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]);
+ }
+#endif
+
+ struct SnapObjectHitDepth *hit_item = hit_depth_create(
+ depth, location, normal, hit->index,
+ data->ob, data->obmat, data->ob_uuid);
+ BLI_addtail(data->hit_list, hit_item);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Internal Object Snapping API
+ * \{ */
+
+static bool snapEdge(
+ ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
+ int result;
+ bool retval = false;
+
+ copy_v3_v3(ray_end, ray_normal_local);
+ mul_v3_fl(ray_end, 2000);
+ add_v3_v3v3(ray_end, ray_start_local, ray_end);
+
+ /* dvec used but we don't care about result */
+ result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec);
+
+ if (result) {
+ float edge_loc[3], vec[3];
+ float mul;
+
+ /* check for behind ray_start */
+ sub_v3_v3v3(dvec, intersect, ray_start_local);
+
+ sub_v3_v3v3(edge_loc, v1co, v2co);
+ sub_v3_v3v3(vec, intersect, v2co);
+
+ mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+
+ if (mul > 1) {
+ mul = 1;
+ copy_v3_v3(intersect, v1co);
+ }
+ else if (mul < 0) {
+ mul = 0;
+ copy_v3_v3(intersect, v2co);
+ }
+
+ if (dot_v3v3(ray_normal_local, dvec) > 0) {
+ float location[3];
+ float new_depth;
+ float screen_loc[2];
+ float new_dist;
+
+ copy_v3_v3(location, intersect);
+
+ mul_m4_v3(obmat, location);
+
+ new_depth = len_v3v3(location, ray_start);
+
+ if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
+ }
+ else {
+ new_dist = TRANSFORM_DIST_MAX_PX;
+ }
+
+ /* 10% threshold if edge is closer but a bit further
+ * this takes care of series of connected edges a bit slanted w.r.t the viewport
+ * otherwise, it would stick to the verts of the closest edge and not slide along merrily
+ * */
+ if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) {
+ float n1[3], n2[3];
+
+ *ray_depth = new_depth;
+ retval = true;
+
+ sub_v3_v3v3(edge_loc, v1co, v2co);
+ sub_v3_v3v3(vec, intersect, v2co);
+
+ mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+
+ if (r_no) {
+ normal_short_to_float_v3(n1, v1no);
+ normal_short_to_float_v3(n2, v2no);
+ interp_v3_v3v3(r_no, n2, n1, mul);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ copy_v3_v3(r_loc, location);
+
+ *dist_px = new_dist;
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapVertex(
+ ARegion *ar, const float vco[3], const float vno[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ bool retval = false;
+ float dvec[3];
+
+ sub_v3_v3v3(dvec, vco, ray_start_local);
+
+ if (dot_v3v3(ray_normal_local, dvec) > 0) {
+ float location[3];
+ float new_depth;
+ float screen_loc[2];
+ float new_dist;
+
+ copy_v3_v3(location, vco);
+
+ mul_m4_v3(obmat, location);
+
+ new_depth = len_v3v3(location, ray_start);
+
+ if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
+ }
+ else {
+ new_dist = TRANSFORM_DIST_MAX_PX;
+ }
+
+
+ if (new_dist <= *dist_px && new_depth < *ray_depth) {
+ *ray_depth = new_depth;
+ retval = true;
+
+ copy_v3_v3(r_loc, location);
+
+ if (r_no) {
+ copy_v3_v3(r_no, vno);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ *dist_px = new_dist;
+ }
+ }
+
+ return retval;
+}
+
+static bool snapArmature(
+ ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+
+ invert_m4_m4(imat, obmat);
+
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+
+ if (arm->edbo) {
+ EditBone *eBone;
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->layer & arm->layer) {
+ /* skip hidden or moving (selected) bones */
+ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(
+ ar, eBone->head, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ retval |= snapVertex(
+ ar, eBone->tail, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(
+ ar, eBone->head, NULL, eBone->tail, NULL,
+ obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (ob->pose && ob->pose->chanbase.first) {
+ bPoseChannel *pchan;
+ Bone *bone;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ /* skip hidden bones */
+ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ const float *head_vec = pchan->pose_head;
+ const float *tail_vec = pchan->pose_tail;
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(
+ ar, head_vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ retval |= snapVertex(
+ ar, tail_vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(
+ ar, head_vec, NULL, tail_vec, NULL,
+ obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapCurve(
+ ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+ int u;
+
+ Nurb *nu;
+
+ /* only vertex snapping mode (eg control points and handles) supported for now) */
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ return retval;
+ }
+
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
+ for (u = 0; u < nu->pntsu; u++) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ if (ob->mode == OB_MODE_EDIT) {
+ if (nu->bezt) {
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
+ break;
+ }
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
+ if (!(nu->bezt[u].f1 & SELECT) &&
+ !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
+ {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ if (!(nu->bezt[u].f3 & SELECT) &&
+ !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
+ {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ else {
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
+ break;
+ }
+ retval |= snapVertex(
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ else {
+ /* curve is not visible outside editmode if nurb length less than two */
+ if (nu->pntsu > 1) {
+ if (nu->bezt) {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ else {
+ retval |= snapVertex(
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+/* may extend later (for now just snaps to empty center) */
+static bool snapEmpty(
+ ARegion *ar, Object *ob, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+
+ if (ob->transflag & OB_DUPLI) {
+ return retval;
+ }
+ /* for now only vertex supported */
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ return retval;
+ }
+
+ invert_m4_m4(imat, obmat);
+
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ const float zero_co[3] = {0.0f};
+ retval |= snapVertex(
+ ar, zero_co, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static bool snapCamera(
+ ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
+ bool retval = false;
+ MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
+ MovieTracking *tracking;
+ float ray_start_local[3], ray_normal_local[3];
+
+ if (clip == NULL) {
+ return retval;
+ }
+ if (object->transflag & OB_DUPLI) {
+ return retval;
+ }
+
+ tracking = &clip->tracking;
+
+ BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
+
+ invert_m4_m4(orig_camera_imat, orig_camera_mat);
+ invert_m4_m4(imat, obmat);
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ MovieTrackingObject *tracking_object;
+
+ for (tracking_object = tracking->objects.first;
+ tracking_object;
+ tracking_object = tracking_object->next)
+ {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ float reconstructed_camera_mat[4][4],
+ reconstructed_camera_imat[4][4];
+ float (*vertex_obmat)[4];
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
+ CFRA, reconstructed_camera_mat);
+
+ invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
+ }
+
+ for (track = tracksbase->first; track; track = track->next) {
+ float bundle_pos[3];
+
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
+ }
+
+ copy_v3_v3(bundle_pos, track->bundle_pos);
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ mul_m4_v3(orig_camera_imat, ray_start_local);
+ mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
+ vertex_obmat = orig_camera_mat;
+ }
+ else {
+ mul_m4_v3(reconstructed_camera_imat, bundle_pos);
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+ vertex_obmat = obmat;
+ }
+
+ retval |= snapVertex(
+ ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
+{
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+}
+
+static bool snapDerivedMesh(
+ SnapObjectContext *sctx,
+ Object *ob, DerivedMesh *dm, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to, bool do_bb,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth, unsigned int ob_index,
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (dm->getNumPolys(dm) == 0) {
+ return retval;
+ }
+ }
+ if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (dm->getNumEdges(dm) == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (dm->getNumVerts(dm) == 0) {
+ return retval;
+ }
+ }
+
+ {
+ const bool do_ray_start_correction = (
+ ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
+ (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
+ bool need_ray_start_correction_init = do_ray_start_correction;
+
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ /* local scale in normal direction */
+ local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ if (do_bb) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ if (bb) {
+ BoundBox bb_temp;
+
+ /* We cannot afford a bounding box with some null dimension, which may happen in some cases...
+ * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
+ bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
+
+ /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
+ * scale up so we can snap against verts & edges on the boundbox, see T46816. */
+ if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
+ bb = &bb_temp;
+ }
+
+ /* was local_depth, see: T47838 */
+ len_diff = BVH_RAYCAST_DIST_MAX;
+
+ if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ need_ray_start_correction_init = false;
+ }
+ }
+
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata = NULL, treedata_stack;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[tree_index];
+
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata && treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ }
+ }
+ }
+ else {
+ if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
+ }
+ }
+
+ if (treedata && treedata->tree == NULL) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
+ break;
+ }
+ }
+
+ if (need_ray_start_correction_init) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ if (treedata && treedata->tree != NULL) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ len_diff = sqrtf(nearest.dist_sq);
+ }
+ }
+ }
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (do_ray_start_correction) {
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ 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.dm = dm;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit;
+
+ hit.index = -1;
+ hit.dist = local_depth;
+
+ if (treedata->tree &&
+ BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+ copy_v3_v3(r_no, hit.no);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = local_depth * local_depth;
+ if (treedata->tree &&
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_start_local, ray_normal_local,
+ &nearest, NULL, NULL) != -1)
+ {
+ const MVert *v = &treedata->vert[nearest.index];
+ float vno[3];
+ normal_short_to_float_v3(vno, v->no);
+ retval = snapVertex(
+ ar, v->co, vno, obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_EDGE:
+ {
+ MVert *verts = dm->getVertArray(dm);
+ MEdge *edges = dm->getEdgeArray(dm);
+ int totedge = dm->getNumEdges(dm);
+
+ for (int i = 0; i < totedge; i++) {
+ MEdge *e = edges + i;
+ retval |= snapEdge(
+ ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
+ obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+
+ break;
+ }
+ }
+
+ if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
+ if (treedata) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ }
+ }
+
+ return retval;
+}
+
+
+static bool snapEditMesh(
+ SnapObjectContext *sctx,
+ Object *ob, BMEditMesh *em, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth, const unsigned int ob_index,
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (em->bm->totface == 0) {
+ return retval;
+ }
+ }
+ if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (em->bm->totedge == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (em->bm->totvert == 0) {
+ return retval;
+ }
+ }
+
+ {
+ const bool do_ray_start_correction = (
+ ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
+ (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
+
+ 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;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ /* local scale in normal direction */
+ local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ SnapObjectData_EditMesh *sod = NULL;
+
+ BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[tree_index];
+ }
+ }
+ else {
+ if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
+ }
+ }
+
+ if (treedata && treedata->tree == NULL) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ BLI_bitmap *looptri_mask = NULL;
+ int looptri_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ em->bm, looptri_mask,
+ sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6);
+ if (looptri_mask) {
+ MEM_freeN(looptri_mask);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BLI_bitmap *verts_mask = NULL;
+ int verts_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_vert_fn) {
+ verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ verts_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_VERTS_OF_MESH, em->bm, verts_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
+ sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
+ if (verts_mask) {
+ MEM_freeN(verts_mask);
+ }
+ break;
+ }
+ }
+ }
+
+ /* 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 (do_ray_start_correction) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ if (treedata && treedata->tree != NULL) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1)
+ {
+ len_diff = sqrtf(nearest.dist_sq);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
+ }
+ }
+ }
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ 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.dm = NULL;
+ 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;
+
+ hit.index = -1;
+ hit.dist = local_depth;
+
+ if (treedata->tree &&
+ BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+ copy_v3_v3(r_no, hit.no);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = hit.index;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = local_depth * local_depth;
+ if (treedata->tree &&
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_start_local, ray_normal_local,
+ &nearest, NULL, NULL) != -1)
+ {
+ const BMVert *v = BM_vert_at_index(em->bm, nearest.index);
+ retval = snapVertex(
+ ar, v->co, v->no, obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_EDGE:
+ {
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
+ int totedge = em->bm->totedge;
+ for (int i = 0; i < totedge; i++) {
+ BMEdge *eed = BM_edge_at_index(em->bm, i);
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
+ {
+ short v1no[3], v2no[3];
+ normal_float_to_short_v3(v1no, eed->v1->no);
+ normal_float_to_short_v3(v2no, eed->v2->no);
+ retval |= snapEdge(
+ ar, eed->v1->co, v1no, eed->v2->co, v2no,
+ obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ }
+
+ break;
+ }
+ }
+
+ if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
+ if (treedata) {
+ free_bvhtree_from_editmesh(treedata);
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapObject(
+ SnapObjectContext *sctx,
+ Object *ob, float obmat[4][4], bool use_obedit, const short snap_to,
+ const float mval[2], float *dist_px, const unsigned int ob_index,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (ob->type == OB_MESH) {
+ BMEditMesh *em;
+
+ if (use_obedit) {
+ em = BKE_editmesh_from_object(ob);
+ retval = snapEditMesh(
+ sctx, ob, em, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_origin,
+ ray_depth, ob_index,
+ 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->scene, ob, em, CD_MASK_BAREMESH, &dm);
+ }
+ else {
+ dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ }
+ retval = snapDerivedMesh(
+ sctx, ob, dm, obmat, mval, dist_px, snap_to, true,
+ ray_start, ray_normal, ray_origin,
+ ray_depth, ob_index,
+ r_loc, r_no, r_index, r_hit_list);
+
+ dm->release(dm);
+ }
+ }
+ else if (ob->type == OB_ARMATURE) {
+ retval = snapArmature(
+ ar, ob, ob->data, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CURVE) {
+ retval = snapCurve(
+ ar, ob, ob->data, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_EMPTY) {
+ retval = snapEmpty(
+ ar, ob, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CAMERA) {
+ retval = snapCamera(
+ ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+
+ if (retval) {
+ if (r_ob) {
+ *r_ob = ob;
+ copy_m4_m4(r_obmat, obmat);
+ }
+ }
+
+ return retval;
+}
+
+static bool snapObjectsRay(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to, const SnapSelect snap_select,
+ const bool use_object_edit_cage,
+ const float mval[2], float *dist_px,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
+{
+ 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->basact;
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ Object *ob = base_act->object;
+
+ retval |= snapObject(
+ sctx, ob, ob->obmat, false, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ 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->base.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
+ (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
+
+ !((ignore_object_selected && (base->flag & (SELECT | 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, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ 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;
+
+ retval |= snapObject(
+ sctx, ob_snap, ob->obmat, use_obedit, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ }
+ }
+
+ return retval;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object Snapping API
+ * \{ */
+
+SnapObjectContext *ED_transform_snap_object_context_create(
+ Main *bmain, Scene *scene, int flag)
+{
+ SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
+
+ sctx->flag = flag;
+
+ sctx->bmain = bmain;
+ sctx->scene = scene;
+
+ return sctx;
+}
+
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(
+ Main *bmain, Scene *scene, int flag,
+ /* extra args for view3d */
+ ARegion *ar, View3D *v3d)
+{
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+
+ sctx->use_v3d = true;
+ sctx->v3d_data.ar = ar;
+ sctx->v3d_data.v3d = v3d;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ return sctx;
+}
+
+static void snap_object_data_free(void *sod_v)
+{
+ switch (((SnapObjectData *)sod_v)->type) {
+ case SNAP_MESH:
+ {
+ SnapObjectData_Mesh *sod = sod_v;
+ for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
+ if (sod->bvh_trees[i]) {
+ free_bvhtree_from_mesh(sod->bvh_trees[i]);
+ }
+ }
+ break;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ SnapObjectData_EditMesh *sod = sod_v;
+ for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
+ if (sod->bvh_trees[i]) {
+ free_bvhtree_from_editmesh(sod->bvh_trees[i]);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
+{
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ BLI_memarena_free(sctx->cache.mem_arena);
+ }
+
+ MEM_freeN(sctx);
+}
+
+void ED_transform_snap_object_context_set_editmesh_callbacks(
+ SnapObjectContext *sctx,
+ bool (*test_vert_fn)(BMVert *, void *user_data),
+ bool (*test_edge_fn)(BMEdge *, void *user_data),
+ bool (*test_face_fn)(BMFace *, void *user_data),
+ void *user_data)
+{
+ sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
+ sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
+ sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
+
+ sctx->callbacks.edit_mesh.user_data = user_data;
+}
+
+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])
+{
+ return snapObjectsRay(
+ sctx,
+ snap_to, params->snap_select, params->use_object_edit_cage,
+ NULL, NULL,
+ ray_start, ray_normal, ray_start, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+}
+
+/**
+ * Fill in a list of all hits.
+ *
+ * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
+ * \param sort: Optionally sort the hits by depth.
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ */
+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)
+{
+ if (ray_depth == -1.0f) {
+ ray_depth = BVH_RAYCAST_DIST_MAX;
+ }
+
+#ifdef DEBUG
+ float ray_depth_prev = ray_depth;
+#endif
+
+ bool retval = snapObjectsRay(
+ sctx,
+ snap_to, params->snap_select, params->use_object_edit_cage,
+ NULL, NULL,
+ ray_start, ray_normal, ray_start, &ray_depth,
+ NULL, NULL, NULL, NULL, NULL,
+ r_hit_list);
+
+ /* meant to be readonly for 'all' hits, ensure it is */
+#ifdef DEBUG
+ BLI_assert(ray_depth_prev == ray_depth);
+#endif
+
+ if (sort) {
+ BLI_listbase_sort(r_hit_list, hit_depth_cmp);
+ }
+
+ return retval;
+}
+
+/**
+ * Convenience function for snap ray-casting.
+ *
+ * Given a ray, cast it into the scene (snapping to faces).
+ *
+ * \return Snap success
+ */
+static bool transform_snap_context_project_ray_impl(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_co[3], float r_no[3])
+{
+ bool ret;
+
+ /* try snap edge, then face if it fails */
+ ret = ED_transform_snap_object_project_ray_ex(
+ sctx,
+ SCE_SNAP_MODE_FACE,
+ params,
+ ray_start, ray_normal, ray_depth,
+ r_co, r_no, NULL,
+ NULL, NULL);
+
+ return ret;
+}
+
+bool ED_transform_snap_object_project_ray(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_origin[3], const float ray_direction[3], float *ray_depth,
+ float r_co[3], float r_no[3])
+{
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
+ }
+
+ float no_fallback[3];
+ if (r_no == NULL) {
+ r_no = no_fallback;
+ }
+
+ return transform_snap_context_project_ray_impl(
+ sctx,
+ params,
+ ray_origin, ray_direction, ray_depth,
+ r_co, r_no);
+}
+
+static bool transform_snap_context_project_view3d_mixed_impl(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ bool use_depth,
+ float r_co[3], float r_no[3])
+{
+ float ray_depth = BVH_RAYCAST_DIST_MAX;
+ bool is_hit = false;
+
+ float r_no_dummy[3];
+ if (r_no == NULL) {
+ r_no = r_no_dummy;
+ }
+
+ const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
+
+ BLI_assert(snap_to_flag != 0);
+ BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
+
+ for (int i = 0; i < 3; i++) {
+ if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
+ if (use_depth == false) {
+ ray_depth = BVH_RAYCAST_DIST_MAX;
+ }
+
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ is_hit = true;
+ }
+ }
+ }
+
+ return is_hit;
+}
+
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param sctx: Snap context.
+ * \param mval_fl: Screenspace coordinate.
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param use_depth: Snap to the closest element, use when using more than one snap type.
+ * \param r_co: hit location.
+ * \param r_no: hit normal (optional).
+ * \return Snap success
+ */
+bool ED_transform_snap_object_project_view3d_mixed(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
+ const struct SnapObjectParams *params,
+ const float mval_fl[2], float *dist_px,
+ bool use_depth,
+ float r_co[3], float r_no[3])
+{
+ return transform_snap_context_project_view3d_mixed_impl(
+ sctx,
+ snap_to_flag, params,
+ mval_fl, dist_px, use_depth,
+ r_co, r_no);
+}
+
+bool ED_transform_snap_object_project_view3d_ex(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ float r_loc[3], float r_no[3], int *r_index)
+{
+ float ray_start[3], ray_normal[3], ray_orgigin[3];
+
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
+ }
+
+ if (!ED_view3d_win_to_ray_ex(
+ sctx->v3d_data.ar, sctx->v3d_data.v3d,
+ mval, ray_orgigin, ray_normal, ray_start, true))
+ {
+ return false;
+ }
+
+ return snapObjectsRay(
+ sctx,
+ snap_to, params->snap_select, params->use_object_edit_cage,
+ mval, dist_px,
+ ray_start, ray_normal, ray_orgigin, ray_depth,
+ r_loc, r_no, r_index, NULL, NULL, NULL);
+}
+
+bool ED_transform_snap_object_project_view3d(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ return ED_transform_snap_object_project_view3d_ex(
+ sctx,
+ snap_to,
+ params,
+ mval, dist_px,
+ ray_depth,
+ r_loc, r_no, NULL);
+}
+
+/**
+ * see: #ED_transform_snap_object_project_ray_all
+ */
+bool ED_transform_snap_object_project_all_view3d_ex(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ float ray_depth, bool sort,
+ ListBase *r_hit_list)
+{
+ float ray_start[3], ray_normal[3];
+
+ if (!ED_view3d_win_to_ray_ex(
+ sctx->v3d_data.ar, sctx->v3d_data.v3d,
+ mval, NULL, ray_normal, ray_start, true))
+ {
+ return false;
+ }
+
+ return ED_transform_snap_object_project_ray_all(
+ sctx,
+ SCE_SNAP_MODE_FACE,
+ params,
+ ray_start, ray_normal, ray_depth, sort,
+ r_hit_list);
+}
+
+/** \} */