Cleanup/Refactor: Split the snap to increments code

Now we have a better distinction of what is snap to grid and what is
snap to increments.

The code also allows the implementation of mixed snap for these modes.
This commit is contained in:
Germano Cavalcante 2020-08-31 10:14:40 -03:00 committed by Germano Cavalcante
parent a1df2fc443
commit 546b900194
Notes: blender-bot 2023-02-13 22:20:49 +01:00
Referenced by commit 4eda60c2d8, Fix T80677: Absolute grid snapping doesn't work with constraints
30 changed files with 208 additions and 180 deletions

View File

@ -79,7 +79,6 @@ typedef struct TransSnap {
bool project;
bool snap_self;
bool peel;
bool snap_spatial_grid;
bool use_backface_culling;
char status;
/* Snapped Element Type (currently for objects only). */

View File

@ -167,7 +167,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3])
{
mul_m3_v3(t->spacemtx_inv, vec);
snapGridIncrement(t, vec);
transform_snap_increment(t, vec);
if (t->flag & T_NULL_ONE) {
if (!(t->con.mode & CON_AXIS0)) {

View File

@ -1014,7 +1014,7 @@ void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float ma
/* scale stroke thickness */
if (td->val) {
snapGridIncrement(t, t->values_final);
transform_snap_increment(t, t->values_final);
applyNumInput(&t->num, t->values_final);
float ratio = t->values_final[0];

View File

@ -67,7 +67,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
time = (float)(t->center2d[0] - mval[0]) * fac;
}
snapGridIncrement(t, &time);
transform_snap_increment(t, &time);
applyNumInput(&t->num, &time);

View File

@ -124,7 +124,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
copy_v3_fl(t->values_final, ratio);
snapGridIncrement(t, t->values_final);
transform_snap_increment(t, t->values_final);
if (applyNumInput(&t->num, t->values_final)) {
constraintNumInput(t, t->values_final);

View File

@ -104,7 +104,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
const float radius_snap = 0.1f;
const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
values.scale *= snap_hack;
snapGridIncrement(t, values.vector);
transform_snap_increment(t, values.vector);
values.scale /= snap_hack;
}
#endif

View File

@ -53,7 +53,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -54,7 +54,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
snapGridIncrement(t, &final);
transform_snap_increment(t, &final);
applyNumInput(&t->num, &final);

View File

@ -53,7 +53,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -55,7 +55,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
CLAMP_MAX(weight, 1.0f);
snapGridIncrement(t, &weight);
transform_snap_increment(t, &weight);
applyNumInput(&t->num, &weight);

View File

@ -55,7 +55,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
CLAMP_MAX(crease, 1.0f);
snapGridIncrement(t, &crease);
transform_snap_increment(t, &crease);
applyNumInput(&t->num, &crease);

View File

@ -99,7 +99,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
float angle = t->values[0];
copy_v3_v3(axis, axis_final);
snapGridIncrement(t, &angle);
transform_snap_increment(t, &angle);
applySnapping(t, &angle);

View File

@ -102,7 +102,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
copy_v3_v3(t->values_final, tvec);
}
else {
// snapGridIncrement(t, t->values);
// transform_snap_increment(t, t->values);
applyNumInput(&t->num, t->values);
copy_v3_v3(t->values_final, t->values);
}

View File

@ -1463,7 +1463,9 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
applySnapping(t, &final);
snapGridIncrement(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
/* only do this so out of range values are not displayed */
if (is_constrained) {

View File

@ -53,7 +53,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -53,7 +53,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -54,7 +54,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -55,7 +55,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
distance = t->values[0];
snapGridIncrement(t, &distance);
transform_snap_increment(t, &distance);
applyNumInput(&t->num, &distance);

View File

@ -91,7 +91,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
copy_v3_fl(t->values_final, ratio);
snapGridIncrement(t, t->values_final);
transform_snap_increment(t, t->values_final);
if (applyNumInput(&t->num, t->values_final)) {
constraintNumInput(t, t->values_final);

View File

@ -200,7 +200,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
snapGridIncrement(t, &final);
transform_snap_increment(t, &final);
float axis_final[3];
/* Use the negative axis to match the default Z axis of the view matrix. */

View File

@ -128,7 +128,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
value = t->values[0];
snapGridIncrement(t, &value);
transform_snap_increment(t, &value);
applyNumInput(&t->num, &value);

View File

@ -56,7 +56,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
distance = t->values[0];
snapGridIncrement(t, &distance);
transform_snap_increment(t, &distance);
applyNumInput(&t->num, &distance);

View File

@ -55,7 +55,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
else {
copy_v3_fl(t->values_final, t->values[0]);
snapGridIncrement(t, t->values_final);
transform_snap_increment(t, t->values_final);
if (applyNumInput(&t->num, t->values_final)) {
constraintNumInput(t, t->values_final);

View File

@ -54,7 +54,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
snapGridIncrement(t, &final);
transform_snap_increment(t, &final);
applyNumInput(&t->num, &final);

View File

@ -54,7 +54,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
ratio = t->values[0];
snapGridIncrement(t, &ratio);
transform_snap_increment(t, &ratio);
applyNumInput(&t->num, &ratio);

View File

@ -93,7 +93,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
copy_v2_v2(phi, t->values);
snapGridIncrement(t, phi);
transform_snap_increment(t, phi);
applyNumInput(&t->num, phi);

View File

@ -362,15 +362,28 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v3_v3(global_dir, t->values);
if ((t->con.mode & CON_APPLY) == 0) {
snapGridIncrement(t, global_dir);
}
if (applyNumInput(&t->num, global_dir)) {
removeAspectRatio(t, global_dir);
}
else {
applySnapping(t, global_dir);
applySnapping(t, global_dir);
if (!validSnap(t) && !(t->con.mode & CON_APPLY)) {
float dist_sq = FLT_MAX;
if (transform_snap_grid(t, global_dir)) {
dist_sq = len_squared_v3v3(t->values, global_dir);
}
/* Check the snap distance to the initial value to work with mixed snap. */
float increment_loc[3];
copy_v3_v3(increment_loc, t->values);
if (transform_snap_increment(t, increment_loc)) {
if ((dist_sq == FLT_MAX) || (len_squared_v3v3(t->values, increment_loc) < dist_sq)) {
copy_v3_v3(global_dir, increment_loc);
}
}
}
}
}
if (t->con.mode & CON_APPLY) {

View File

@ -587,7 +587,9 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
applySnapping(t, &final);
snapGridIncrement(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
/* only do this so out of range values are not displayed */
if (is_constrained) {

View File

@ -378,30 +378,14 @@ void applyProject(TransInfo *t)
void applyGridAbsolute(TransInfo *t)
{
float grid_size = 0.0f;
GearsType grid_action;
int i;
if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
return;
}
grid_action = BIG_GEARS;
if (t->modifiers & MOD_PRECISION) {
grid_action = SMALL_GEARS;
}
float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[2] : t->snap_spatial[1];
switch (grid_action) {
case NO_GEARS:
grid_size = t->snap_spatial[0];
break;
case BIG_GEARS:
grid_size = t->snap_spatial[1];
break;
case SMALL_GEARS:
grid_size = t->snap_spatial[2];
break;
}
/* early exit on unusable grid size */
if (grid_size == 0.0f) {
return;
@ -445,7 +429,12 @@ void applyGridAbsolute(TransInfo *t)
void applySnapping(TransInfo *t, float *vec)
{
/* Each Trans Data already makes the snap to face */
if (doForceIncrementSnap(t) || (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE)) {
if (doForceIncrementSnap(t)) {
return;
}
if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
/* The snap has already been resolved for each transdata. */
return;
}
@ -559,6 +548,12 @@ static void initSnappingMode(TransInfo *t)
}
t->tsnap.mode = ts->snap_mode;
if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
/* Special case in which snap to increments is transformed to snap to grid. */
t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
t->tsnap.mode |= SCE_SNAP_MODE_GRID;
}
}
if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && (t->flag & T_CAMERA) == 0) {
@ -600,7 +595,7 @@ static void initSnappingMode(TransInfo *t)
}
}
else {
/* Grid if snap is not possible */
/* Increment if snap is not possible */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
}
@ -613,7 +608,7 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
}
else {
/* Always grid outside of 3D view */
/* Always increment outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
@ -686,11 +681,6 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) != 0);
t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) != 0);
}
/* for now only 3d view (others can be added if we want) */
if (t->spacetype == SPACE_VIEW3D) {
t->tsnap.snap_spatial_grid = ((t->settings->snap_flag & SCE_SNAP_ABS_GRID) != 0);
}
}
t->tsnap.target = snap_target;
@ -832,11 +822,6 @@ void getSnapPoint(const TransInfo *t, float vec[3])
/** \name Calc Snap (Generic)
* \{ */
static void UNUSED_FUNCTION(CalcSnapGrid)(TransInfo *t, float *UNUSED(vec))
{
snapGridIncrementAction(t, t->tsnap.snapPoint, BIG_GEARS);
}
static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
{
if (t->spacetype == SPACE_VIEW3D) {
@ -1407,40 +1392,6 @@ void snapFrameTransform(TransInfo *t,
/*================================================================*/
static void applyGridIncrement(
TransInfo *t, float *val, int max_index, const float fac[3], GearsType action);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action)
{
float fac[3];
fac[NO_GEARS] = t->snap[0];
fac[BIG_GEARS] = t->snap[1];
fac[SMALL_GEARS] = t->snap[2];
applyGridIncrement(t, val, t->idx_max, fac, action);
}
void snapGridIncrement(TransInfo *t, float *val)
{
GearsType action;
/* only do something if using absolute or incremental grid snapping
* and there is no valid snap point */
if ((!(t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) || validSnap(t)) &&
!doForceIncrementSnap(t)) {
return;
}
action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
if (action == BIG_GEARS && (t->modifiers & MOD_PRECISION)) {
action = SMALL_GEARS;
}
snapGridIncrementAction(t, val, action);
}
void snapSequenceBounds(TransInfo *t, const int mval[2])
{
/* Reuse increment, strictly speaking could be another snap mode, but leave as is. */
@ -1461,23 +1412,140 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
t->values[0] = frame_near - frame_snap;
}
static void applyGridIncrement(
TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
static void snap_grid_apply_ex(
TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
{
float asp_local[3] = {1, 1, 1};
const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
const float *asp = use_aspect ? t->aspect : asp_local;
int i;
const float *center_global = t->center_global;
const float *asp = t->aspect;
bool use_local_axis = false;
BLI_assert((t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) ||
doForceIncrementSnap(t));
/* 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_MEDIAN);
center_global = cd->global;
}
if (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) {
use_local_axis = true;
}
for (int 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 = grid_dist * asp[i];
if (use_local_axis) {
float local_axis[3];
float pos_on_axis[3];
copy_v3_v3(local_axis, t->spacemtx[i]);
copy_v3_v3(pos_on_axis, t->spacemtx[i]);
/* amount of movement on axis from initial pos */
mul_v3_fl(pos_on_axis, loc[i]);
/* actual global position on axis */
add_v3_v3(pos_on_axis, center_global);
float min_dist = INFINITY;
for (int j = 0; j < 3; j++) {
if (fabs(local_axis[j]) < 0.01f) {
/* Ignore very small (normalized) axis changes */
continue;
}
/* closest point on grid */
float grid_p = iter_fac * roundf(pos_on_axis[j] / iter_fac);
float dist_p = fabs((grid_p - pos_on_axis[j]) / local_axis[j]);
/* The amount of distance needed to travel along the
* local axis to snap to the closest grid point */
/* in the global j axis direction */
float move_dist = (grid_p - center_global[j]) / local_axis[j];
if (dist_p < min_dist) {
min_dist = dist_p;
r_out[i] = move_dist;
}
}
}
else {
r_out[i] = iter_fac * roundf((loc[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
}
static void snap_grid_apply(TransInfo *t, int max_index, const float grid_dist, float *r_val)
{
BLI_assert(t->tsnap.mode & SCE_SNAP_MODE_GRID);
BLI_assert(max_index <= 2);
/* Early bailing out if no need to snap */
if (fac[action] == 0.0f) {
if (grid_dist == 0.0f) {
return;
}
/* absolute snapping on grid based on global center.
* for now only 3d view (others can be added if we want) */
snap_grid_apply_ex(t, max_index, grid_dist, r_val, r_val);
}
bool transform_snap_grid(TransInfo *t, float *val)
{
if ((!(t->tsnap.mode & SCE_SNAP_MODE_GRID)) || validSnap(t)) {
/* Don't do grid snapping if there is a valid snap point. */
return false;
}
if (t->spacetype != SPACE_VIEW3D) {
return false;
}
if (t->mode != TFM_TRANSLATION) {
return false;
}
float grid_dist = activeSnap(t) ? (t->modifiers & MOD_PRECISION) ? t->snap[2] : t->snap[1] :
t->snap[0];
snap_grid_apply(t, t->idx_max, grid_dist, val);
return true;
}
static void snap_increment_apply_ex(TransInfo *t,
const int max_index,
const float increment_val,
const float aspect[3],
const float loc[3],
float r_out[3])
{
/* relative snapping in fixed increments */
for (int i = 0; i <= max_index; i++) {
const float iter_fac = increment_val * aspect[i];
r_out[i] = iter_fac * roundf(loc[i] / iter_fac);
}
}
static void snap_increment_apply(TransInfo *t,
int max_index,
const float increment_dist,
float *r_val)
{
BLI_assert((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) || doForceIncrementSnap(t));
BLI_assert(max_index <= 2);
/* Early bailing out if no need to snap */
if (increment_dist == 0.0f) {
return;
}
float asp_local[3] = {1, 1, 1};
const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
const float *asp = use_aspect ? t->aspect : asp_local;
if (use_aspect) {
/* custom aspect for fcurve */
if (t->spacetype == SPACE_GRAPH) {
@ -1491,76 +1559,26 @@ static void applyGridIncrement(
}
}
/* 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;
bool use_local_axis = false;
snap_increment_apply_ex(t, max_index, increment_dist, asp, r_val, r_val);
}
/* 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_MEDIAN);
center_global = cd->global;
}
if (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) {
use_local_axis = true;
}
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];
if (use_local_axis) {
float local_axis[3];
float pos_on_axis[3];
copy_v3_v3(local_axis, t->spacemtx[i]);
copy_v3_v3(pos_on_axis, t->spacemtx[i]);
/* amount of movement on axis from initial pos */
mul_v3_fl(pos_on_axis, val[i]);
/* actual global position on axis */
add_v3_v3(pos_on_axis, center_global);
float min_dist = INFINITY;
for (int j = 0; j < 3; j++) {
if (fabs(local_axis[j]) < 0.01f) {
/* Ignore very small (normalized) axis changes */
continue;
}
/* closest point on grid */
float grid_p = iter_fac * roundf(pos_on_axis[j] / iter_fac);
float dist_p = fabs((grid_p - pos_on_axis[j]) / local_axis[j]);
/* The amount of distance needed to travel along the
* local axis to snap to the closest grid point */
/* in the global j axis direction */
float move_dist = (grid_p - center_global[j]) / local_axis[j];
if (dist_p < min_dist) {
min_dist = dist_p;
val[i] = move_dist;
}
}
}
else {
val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
bool transform_snap_increment(TransInfo *t, float *val)
{
if (!(t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && !doForceIncrementSnap(t)) {
return false;
}
else {
/* relative snapping in fixed increments */
for (i = 0; i <= max_index; i++) {
const float iter_fac = fac[action] * asp[i];
val[i] = iter_fac * roundf(val[i] / iter_fac);
}
if (t->spacetype != SPACE_VIEW3D && validSnap(t)) {
/* Only do something if using absolute or incremental grid snapping
* and there is no valid snap point. */
return false;
}
float increment_dist = activeSnap(t) ? (t->modifiers & MOD_PRECISION) ? t->snap[2] : t->snap[1] :
t->snap[0];
snap_increment_apply(t, t->idx_max, increment_dist, val);
return true;
}
/** \} */

View File

@ -54,16 +54,10 @@ void snapFrameTransform(struct TransInfo *t,
/* return args */
float *r_val);
typedef enum {
NO_GEARS = 0,
BIG_GEARS = 1,
SMALL_GEARS = 2,
} GearsType;
bool transformModeUseSnap(const TransInfo *t);
void snapGridIncrement(TransInfo *t, float *val);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action);
bool transform_snap_increment(TransInfo *t, float *val);
bool transform_snap_grid(TransInfo *t, float *val);
void snapSequenceBounds(TransInfo *t, const int mval[2]);