Fix #113505: Scale strips in nla with snap active seems broken #113554

Merged
Germano Cavalcante merged 7 commits from mano-wii/blender:fix_113505 into blender-v4.0-release 2023-10-20 14:24:57 +02:00
5 changed files with 130 additions and 63 deletions

View File

@ -634,67 +634,12 @@ static void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
static void invert_snap(eSnapMode &snap_mode)
{
if (snap_mode & SCE_SNAP_TO_FRAME) {
snap_mode &= ~SCE_SNAP_TO_FRAME;
snap_mode |= SCE_SNAP_TO_SECOND;
}
else if (snap_mode & SCE_SNAP_TO_SECOND) {
snap_mode &= ~SCE_SNAP_TO_SECOND;
snap_mode |= SCE_SNAP_TO_FRAME;
}
}
static void snap_transform_data(TransInfo *t, TransDataContainer *tc)
{
/* handle auto-snapping
* NOTE: only do this when transform is still running, or we can't restore
*/
if (t->state == TRANS_CANCEL) {
return;
}
if ((t->tsnap.flag & SCE_SNAP) == 0) {
return;
}
eSnapMode snap_mode = t->tsnap.mode;
if (t->modifiers & MOD_SNAP_INVERT) {
invert_snap(snap_mode);
}
float offset = 0;
float smallest_snap_delta = FLT_MAX;
/* In order to move the strip in a block and not each end individually,
* find the minimal snap offset first and then shift the whole strip by that amount. */
for (int i = 0; i < tc->data_len; i++) {
TransData td = tc->data[i];
float snap_value;
transform_snap_anim_flush_data(t, &td, snap_mode, &snap_value);
/* The snap_delta measures how far from the unsnapped position the value has moved. */
const float snap_delta = *td.loc - snap_value;
if (fabs(snap_delta) < fabs(smallest_snap_delta)) {
offset = snap_value - td.iloc[0];
smallest_snap_delta = snap_delta;
}
}
for (int i = 0; i < tc->data_len; i++) {
TransData td = tc->data[i];
*td.loc = td.iloc[0] + offset;
}
}
static void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
snap_transform_data(t, tc);
/* For each strip we've got, perform some additional validation of the values
* that got set before using RNA to set the value (which does some special
* operations when setting these values to make sure that everything works ok).

View File

@ -33,6 +33,15 @@
/** \name Transform (Animation Time Scale)
* \{ */
static void timescale_snap_apply_fn(TransInfo *t, float vec[3])
{
float point[3];
getSnapPoint(t, point);
const float fac = (point[0] - t->center_global[0]) /

can be const

can be const
(t->tsnap.snap_source[0] - t->center_global[0]);
vec[0] = fac;
}
static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@ -84,6 +93,9 @@ static void applyTimeScale(TransInfo *t)
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
applyNumInput(&t->num, &t->vec[0]);
transform_snap_mixed_apply(t, &t->vec[0]);
t->values_final[0] = t->vec[0];
headerTimeScale(t, str);
@ -94,6 +106,15 @@ static void applyTimeScale(TransInfo *t)
ED_area_status_text(t->area, str);
}
static void timescale_transform_matrix_fn(TransInfo *t, float mat_xform[4][4])
{

those too can all be const

those too can all be const
const float i_loc = mat_xform[3][0];
const float startx = t->center_global[0];
const float fac = t->values_final[0];
const float loc = ((i_loc - startx) * fac) + startx;
mat_xform[3][0] = loc;
}
static void initTimeScale(TransInfo *t, wmOperator * /*op*/)
{
float center[2];
@ -141,9 +162,9 @@ TransModeInfo TransMode_timescale = {
/*flags*/ T_NULL_ONE,
/*init_fn*/ initTimeScale,
/*transform_fn*/ applyTimeScale,
/*transform_matrix_fn*/ nullptr,
/*transform_matrix_fn*/ timescale_transform_matrix_fn,
/*handle_event_fn*/ nullptr,
/*snap_distance_fn*/ nullptr,
/*snap_apply_fn*/ nullptr,
/*snap_apply_fn*/ timescale_snap_apply_fn,
/*draw_fn*/ nullptr,
};

View File

@ -68,6 +68,7 @@ static void snap_target_view3d_fn(TransInfo *t, float *vec);
static void snap_target_uv_fn(TransInfo *t, float *vec);
static void snap_target_node_fn(TransInfo *t, float *vec);
static void snap_target_sequencer_fn(TransInfo *t, float *vec);
static void snap_target_nla_fn(TransInfo *t, float *vec);
static void snap_source_median_fn(TransInfo *t);
static void snap_source_center_fn(TransInfo *t);
@ -963,6 +964,11 @@ static void setSnappingCallback(TransInfo *t)
/* The target is calculated along with the snap point. */
return;
}
else if (t->spacetype == SPACE_NLA) {
t->tsnap.snap_target_fn = snap_target_nla_fn;
/* The target is calculated along with the snap point. */
return;
}
else {
return;
}
@ -1200,6 +1206,17 @@ static void snap_target_sequencer_fn(TransInfo *t, float * /*vec*/)
}
}
static void snap_target_nla_fn(TransInfo *t, float *vec)
{
BLI_assert(t->spacetype == SPACE_NLA);
if (transform_snap_nla_calc(t, vec)) {
t->tsnap.status |= (SNAP_TARGET_FOUND | SNAP_SOURCE_FOUND);
}
else {
t->tsnap.status &= ~(SNAP_TARGET_FOUND | SNAP_SOURCE_FOUND);
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -85,3 +85,4 @@ void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
eSnapMode autosnap,
float *r_val_final);
bool transform_snap_nla_calc(TransInfo *t, float *vec);

View File

@ -8,6 +8,9 @@
#include "DNA_anim_types.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector.h"
#include "BKE_context.h"
#include "BKE_nla.h"
@ -17,6 +20,8 @@
#include "transform.hh"
#include "transform_snap.hh"
using namespace blender;
/* -------------------------------------------------------------------- */
/** \name Snapping in Anim Editors
* \{ */
@ -68,14 +73,11 @@ void snapFrameTransform(TransInfo *t,
}
}
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eSnapMode snap_mode,
float *r_val_final)
static void transform_snap_anim_flush_data_ex(
TransInfo *t, TransData *td, float val, const eSnapMode snap_mode, float *r_val_final)
{
BLI_assert(t->tsnap.flag);
float val = td->loc[0];
float ival = td->iloc[0];
AnimData *adt = static_cast<AnimData *>(!ELEM(t->spacetype, SPACE_NLA, SPACE_SEQ) ? td->extra :
nullptr);
@ -96,4 +98,85 @@ void transform_snap_anim_flush_data(TransInfo *t,
*r_val_final = val;
}
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eSnapMode snap_mode,
float *r_val_final)
{
transform_snap_anim_flush_data_ex(t, td, td->loc[0], snap_mode, r_val_final);
}
static void invert_snap(eSnapMode &snap_mode)
{
if (snap_mode & SCE_SNAP_TO_FRAME) {
snap_mode &= ~SCE_SNAP_TO_FRAME;
snap_mode |= SCE_SNAP_TO_SECOND;
}
else if (snap_mode & SCE_SNAP_TO_SECOND) {
snap_mode &= ~SCE_SNAP_TO_SECOND;
snap_mode |= SCE_SNAP_TO_FRAME;
}
}
/* WORKAROUND: The source position is based on the transformed elements.
* However, at this stage, the transformation has not yet been applied.
* So apply the transformation here. */
static float2 nla_transform_apply(TransInfo *t, float *vec, float2 &ival)
{
float4x4 mat = float4x4::identity();
float values_final_prev[4];
const size_t values_final_size = sizeof(*t->values_final) * size_t(t->idx_max + 1);
memcpy(values_final_prev, t->values_final, values_final_size);
memcpy(t->values_final, vec, values_final_size);
mat[3][0] = ival[0];
mat[3][1] = ival[1];
transform_apply_matrix(t, mat.ptr());
memcpy(t->values_final, values_final_prev, values_final_size);
return mat.location().xy();
}
bool transform_snap_nla_calc(TransInfo *t, float *vec)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
eSnapMode snap_mode = t->tsnap.mode;
if (t->modifiers & MOD_SNAP_INVERT) {
invert_snap(snap_mode);
}
float best_dist = FLT_MAX;
float2 best_source = float2(0);
float2 best_target = float2(0);
bool found = false;
for (int i = 0; i < tc->data_len; i++) {
TransData *td = &tc->data[i];
float2 snap_source = td->iloc;
float2 snap_target = nla_transform_apply(t, vec, snap_source);
transform_snap_anim_flush_data_ex(t, td, snap_target[0], snap_mode, &snap_target[0]);
const int dist = abs(snap_target[0] - snap_source[0]);

const

const
if (dist < best_dist) {
if (dist != 0) {
/* Prioritize non-zero dist for scale. */
best_dist = dist;
}
else if (found) {
continue;
}
best_source = snap_source;
best_target = snap_target;
found = true;
}
}
copy_v2_v2(t->tsnap.snap_source, best_source);
copy_v2_v2(t->tsnap.snap_target, best_target);
return found;
}
/** \} */