Blender V5.0
transform_snap_animation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10#include "BLI_math_vector.h"
11
12#include "BKE_nla.hh"
13
14#include "DNA_space_types.h"
15
16#include "ED_markers.hh"
17
18#include "transform.hh"
19#include "transform_snap.hh"
20
21namespace blender::ed::transform {
22
23/* -------------------------------------------------------------------- */
26
28 const eSnapMode snap_mode,
29 const float val_initial,
30 const float val_final,
31 float *r_val_final)
32{
33 float deltax = val_final - val_initial;
34 /* This is needed for the FPS macro. */
35 const Scene *scene = t->scene;
36 const eSnapFlag snap_flag = t->tsnap.flag;
37
38 switch (snap_mode) {
39 case SCE_SNAP_TO_FRAME: {
40 if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
41 *r_val_final = floorf(val_final + 0.5f);
42 }
43 else {
44 deltax = floorf(deltax + 0.5f);
45 *r_val_final = val_initial + deltax;
46 }
47 break;
48 }
49 case SCE_SNAP_TO_SECOND: {
50 if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
51 *r_val_final = floorf((val_final / scene->frames_per_second()) + 0.5) *
52 scene->frames_per_second();
53 }
54 else {
55 deltax = float(floor((deltax / scene->frames_per_second()) + 0.5) *
56 scene->frames_per_second());
57 *r_val_final = val_initial + deltax;
58 }
59 break;
60 }
62 /* Snap to nearest marker. */
63 /* TODO: need some more careful checks for where data comes from. */
64 const float nearest_marker_time = float(
66 *r_val_final = nearest_marker_time;
67 break;
68 }
69 default: {
70 *r_val_final = val_final;
71 break;
72 }
73 }
74}
75
77 TransInfo *t, TransData *td, float val, const eSnapMode snap_mode, float *r_val_final)
78{
80
81 float ival = td->iloc[0];
82
83 AnimData *adt = nullptr;
85 /* #TD_GREASE_PENCIL_FRAME stores #bke::greasepencil::Layer* in
86 * `td->extra`, and not the #AnimData. */
87 adt = static_cast<AnimData *>(td->extra);
88 }
89
90 /* Convert frame to nla-action time (if needed). */
91 if (adt) {
94 }
95
96 snapFrameTransform(t, snap_mode, ival, val, &val);
97
98 /* Convert frame out of nla-action time. */
99 if (adt) {
101 }
102
103 *r_val_final = val;
104}
105
107 TransData *td,
108 const eSnapMode snap_mode,
109 float *r_val_final)
110{
111 transform_snap_anim_flush_data_ex(t, td, td->loc[0], snap_mode, r_val_final);
112}
113
114static void invert_snap(eSnapMode &snap_mode)
115{
116 if (snap_mode & SCE_SNAP_TO_FRAME) {
117 snap_mode &= ~SCE_SNAP_TO_FRAME;
118 snap_mode |= SCE_SNAP_TO_SECOND;
119 }
120 else if (snap_mode & SCE_SNAP_TO_SECOND) {
121 snap_mode &= ~SCE_SNAP_TO_SECOND;
122 snap_mode |= SCE_SNAP_TO_FRAME;
123 }
124}
125
126/* WORKAROUND: The source position is based on the transformed elements.
127 * However, at this stage, the transformation has not yet been applied.
128 * So apply the transformation here. */
129static float2 nla_transform_apply(TransInfo *t, const float *vec, const float2 &ival)
130{
132
133 float values_final_prev[4];
134 const size_t values_final_size = sizeof(*t->values_final) * size_t(t->idx_max + 1);
135 memcpy(values_final_prev, t->values_final, values_final_size);
136 memcpy(t->values_final, vec, values_final_size);
137
138 mat[3][0] = ival[0];
139 mat[3][1] = ival[1];
140 transform_apply_matrix(t, mat.ptr());
141
142 memcpy(t->values_final, values_final_prev, values_final_size);
143
144 return mat.location().xy();
145}
146
148{
150
151 eSnapMode snap_mode = t->tsnap.mode;
152 if (t->modifiers & MOD_SNAP_INVERT) {
153 invert_snap(snap_mode);
154 }
155
156 float best_dist = FLT_MAX;
157 float2 best_source = float2(0);
158 float2 best_target = float2(0);
159 bool found = false;
160
161 for (int i = 0; i < tc->data_len; i++) {
162 TransData *td = &tc->data[i];
163 float2 snap_source = td->iloc;
164 float2 snap_target = nla_transform_apply(t, vec, snap_source);
165
166 transform_snap_anim_flush_data_ex(t, td, snap_target[0], snap_mode, &snap_target[0]);
167 const int dist = abs(snap_target[0] - snap_source[0]);
168 if (dist < best_dist) {
169 if (dist != 0) {
170 /* Prioritize non-zero dist for scale. */
171 best_dist = dist;
172 }
173 else if (found) {
174 continue;
175 }
176 best_source = snap_source;
177 best_target = snap_target;
178 found = true;
179 }
180 }
181
182 copy_v2_v2(t->tsnap.snap_source, best_source);
183 copy_v2_v2(t->tsnap.snap_target, best_target);
184 return found;
185}
186
188
189} // namespace blender::ed::transform
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, eNlaTime_ConvertModes mode)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void copy_v2_v2(float r[2], const float a[2])
#define ELEM(...)
@ SCE_SNAP_ABS_TIME_STEP
@ SCE_SNAP_TO_MARKERS
@ SCE_SNAP_TO_FRAME
@ SCE_SNAP_TO_SECOND
@ SPACE_NLA
@ SPACE_SEQ
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
nullptr float
#define abs
#define floor
static void invert_snap(eSnapMode &snap_mode)
static float2 nla_transform_apply(TransInfo *t, const float *vec, const float2 &ival)
void transform_snap_anim_flush_data(TransInfo *t, TransData *td, eSnapMode snap_mode, float *r_val_final)
void snapFrameTransform(TransInfo *t, eSnapMode snap_mode, float val_initial, float val_final, float *r_val_final)
bool transform_apply_matrix(TransInfo *t, float mat[4][4])
static void transform_snap_anim_flush_data_ex(TransInfo *t, TransData *td, float val, const eSnapMode snap_mode, float *r_val_final)
bool transform_snap_nla_calc(TransInfo *t, float *vec)
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
#define floorf
#define FLT_MAX
Definition stdcycles.h:14
ListBase markers
const c_style_mat & ptr() const
VecBase< T, 2 > xy() const
i
Definition text_draw.cc:230
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:39