Blender V5.0
transform_input.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstdlib>
11
12#include "DNA_screen_types.h"
13#include "DNA_sequence_types.h"
14#include "DNA_space_types.h"
15#include "DNA_userdef_types.h"
16
17#include "BKE_context.hh"
18
19#include "BLI_math_vector.h"
20#include "BLI_utildefines.h"
21
22#include "WM_api.hh"
23#include "WM_types.hh"
24
25#include "transform.hh"
26#include "transform_mode.hh"
27
28#include "ED_sequencer.hh"
29
30#include "SEQ_time.hh"
31
32#include "MEM_guardedalloc.h"
33
34namespace blender::ed::transform {
35
36/* -------------------------------------------------------------------- */
39
41static void InputVector(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
42{
43 convertViewVec(t, output, mval[0] - mi->imval[0], mval[1] - mi->imval[1]);
44}
45
47static void InputSpring(TransInfo * /*t*/, MouseInput *mi, const double mval[2], float output[3])
48{
49 double dx, dy;
50 float ratio;
51
52 dx = double(mi->center[0]) - mval[0];
53 dy = double(mi->center[1]) - mval[1];
54 ratio = hypot(dx, dy) / double(mi->factor);
55
56 output[0] = ratio;
57}
58
60static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
61{
62 InputSpring(t, mi, mval, output);
63
64 /* Flip scale. */
65 /* Values can become really big when zoomed in so use longs #26598. */
66 if ((int64_t(int(mi->center[0]) - mval[0]) * int64_t(int(mi->center[0]) - mi->imval[0]) +
67 int64_t(int(mi->center[1]) - mval[1]) * int64_t(int(mi->center[1]) - mi->imval[1])) < 0)
68 {
69 output[0] *= -1.0f;
70 }
71}
72
74static void InputSpringDelta(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
75{
76 InputSpring(t, mi, mval, output);
77 output[0] -= 1.0f;
78}
79
81static void InputTrackBall(TransInfo * /*t*/,
82 MouseInput *mi,
83 const double mval[2],
84 float output[3])
85{
86 output[0] = float(mi->imval[1] - mval[1]);
87 output[1] = float(mval[0] - mi->imval[0]);
88
89 output[0] *= mi->factor;
90 output[1] *= mi->factor;
91}
92
95 MouseInput *mi,
96 const double mval[2],
97 float output[3])
98{
99 const int winx = t->region ? t->region->winx : 1;
100
101 output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f;
102}
103
106 MouseInput *mi,
107 const double mval[2],
108 float output[3])
109{
110 float vec[3];
111
112 InputVector(t, mi, mval, vec);
113 project_v3_v3v3(vec, vec, t->viewinv[0]);
114
115 output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f;
116}
117
118static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
119{
120 const int winy = t->region ? t->region->winy : 1;
121
122 /* Dragging up increases (matching viewport zoom). */
123 output[0] = ((mval[1] - mi->imval[1]) / winy) * 2.0f;
124}
125
128 MouseInput *mi,
129 const double mval[2],
130 float output[3])
131{
132 float vec[3];
133
134 InputVector(t, mi, mval, vec);
135 project_v3_v3v3(vec, vec, t->viewinv[1]);
136
137 /* Dragging up increases (matching viewport zoom). */
138 output[0] = dot_v3v3(t->viewinv[1], vec) * 2.0f;
139}
140
142static void InputCustomRatioFlip(TransInfo * /*t*/,
143 MouseInput *mi,
144 const double mval[2],
145 float output[3])
146{
147 double length;
148 double distance;
149 double dx, dy;
150 const int *data = static_cast<const int *>(mi->data);
151
152 if (data) {
153 int mdx, mdy;
154 dx = data[2] - data[0];
155 dy = data[3] - data[1];
156
157 length = hypot(dx, dy);
158
159 mdx = mval[0] - data[2];
160 mdy = mval[1] - data[3];
161
162 distance = (length != 0.0) ? (mdx * dx + mdy * dy) / length : 0.0;
163
164 output[0] = (length != 0.0) ? (distance / length) : 0.0;
165 }
166}
167
169static void InputCustomRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
170{
171 InputCustomRatioFlip(t, mi, mval, output);
172 output[0] = -output[0];
173}
174
176 double angle;
177 double mval_prev[2];
178};
179
181static void InputAngle(TransInfo * /*t*/, MouseInput *mi, const double mval[2], float output[3])
182{
183 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
184 float dir_prev[2], dir_curr[2], mi_center[2];
185 copy_v2_v2(mi_center, mi->center);
186
187 sub_v2_v2v2(dir_prev, float2{float(data->mval_prev[0]), float(data->mval_prev[1])}, mi_center);
188 sub_v2_v2v2(dir_curr, float2{float(mval[0]), float(mval[1])}, mi_center);
189
190 if (normalize_v2(dir_prev) && normalize_v2(dir_curr)) {
191 float dphi = angle_normalized_v2v2(dir_prev, dir_curr);
192
193 if (cross_v2v2(dir_prev, dir_curr) > 0.0f) {
194 dphi = -dphi;
195 }
196
197 data->angle += double(dphi) * (mi->precision ? double(mi->precision_factor) : 1.0);
198
199 data->mval_prev[0] = mval[0];
200 data->mval_prev[1] = mval[1];
201 }
202
203 output[0] = data->angle;
204}
205
206static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
207{
208 float toutput[3];
209
210 InputAngle(t, mi, mval, output);
211 InputSpring(t, mi, mval, toutput);
212
213 output[1] = toutput[0];
214}
215
217
218/* -------------------------------------------------------------------- */
224
226 MouseInput *mi,
227 const int mval_start[2],
228 const int mval_end[2])
229{
230 int *data;
231
232 mi->data = MEM_reallocN(mi->data, sizeof(int[4]));
233
234 data = static_cast<int *>(mi->data);
235
236 data[0] = mval_start[0];
237 data[1] = mval_start[1];
238 data[2] = mval_end[0];
239 data[3] = mval_end[1];
240}
241
243{
245 const int win_axis =
246 t->region ? ((abs(int(t->region->winx * dir[0])) + abs(int(t->region->winy * dir[1]))) / 2) :
247 1;
248 const int2 mval_start = int2(mi->imval + dir * win_axis);
249 const int2 mval_end = int2(mi->imval);
250 setCustomPoints(t, mi, mval_start, mval_end);
251}
252
254
255/* -------------------------------------------------------------------- */
258
260{
261 MouseInput *mi = &t->mouse;
262
263 mi->imval = mval;
264
265 if (mi->data && ELEM(mi->apply, InputAngle, InputAngleSpring)) {
266 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
267 data->mval_prev[0] = mi->imval[0];
268 data->mval_prev[1] = mi->imval[1];
269 data->angle = 0.0f;
270 }
271}
272
274 TransInfo *t, MouseInput *mi, const float2 &center, const float2 &mval, const bool precision)
275{
276 mi->factor = 0;
277 mi->precision = precision;
278
279 mi->center = center;
280
281 mi->post = nullptr;
282
283 transform_input_reset(t, mval);
284}
285
287{
288 float mdir[2] = {float(mi->center[1] - mi->imval[1]), float(mi->center[0] - mi->imval[0])};
289
290 mi->factor = len_v2(mdir);
291
292 if (mi->factor == 0.0f) {
293 mi->factor = 1.0f; /* Prevent inf. */
294 }
295}
296
298{
299 if ((strip->flag & SEQ_LEFTSEL) != 0) {
301 }
302 if ((strip->flag & SEQ_RIGHTSEL) != 0) {
304 }
306}
307
309{
310 const Scene *scene = t->scene;
312
313 if (strips.size() == 1) {
314 return transform_seq_slide_strip_cursor_get(strips[0]);
315 }
316 if (strips.size() == 2) {
317 Strip *strip1 = strips[0];
318 Strip *strip2 = strips[1];
319
320 if (seq::time_left_handle_frame_get(scene, strip1) >
321 seq::time_left_handle_frame_get(scene, strip2))
322 {
323 SWAP(Strip *, strip1, strip2);
324 }
325
326 if (strip1->channel != strip2->channel) {
328 }
329
330 if (seq::time_right_handle_frame_get(scene, strip1) !=
331 seq::time_left_handle_frame_get(scene, strip2))
332 {
334 }
335
336 const int cursor1 = transform_seq_slide_strip_cursor_get(strip1);
337 const int cursor2 = transform_seq_slide_strip_cursor_get(strip2);
338
339 if (cursor1 == WM_CURSOR_RIGHT_HANDLE && cursor2 == WM_CURSOR_LEFT_HANDLE) {
341 }
342 }
343
345}
346
348{
349 /* In case we allocate a new value. */
350 void *mi_data_prev = mi->data;
351
352 mi->use_virtual_mval = true;
353 mi->precision_factor = 1.0f / 10.0f;
354
355 switch (mode) {
356 case INPUT_VECTOR:
357 mi->apply = InputVector;
358 t->helpline = HLP_NONE;
359 break;
360 case INPUT_SPRING:
362 mi->apply = InputSpring;
363 t->helpline = HLP_SPRING;
364 break;
368 t->helpline = HLP_SPRING;
369 break;
373 t->helpline = HLP_SPRING;
374 break;
375 case INPUT_ANGLE:
376 case INPUT_ANGLE_SPRING: {
378 mi->use_virtual_mval = false;
379 mi->precision_factor = 1.0f / 30.0f;
380 data = MEM_callocN<InputAngle_Data>("angle accumulator");
381 data->mval_prev[0] = mi->imval[0];
382 data->mval_prev[1] = mi->imval[1];
383 mi->data = data;
384 if (mode == INPUT_ANGLE) {
385 mi->apply = InputAngle;
386 }
387 else {
390 }
391 t->helpline = HLP_ANGLE;
392 break;
393 }
394 case INPUT_TRACKBALL:
395 mi->precision_factor = 1.0f / 30.0f;
396 /* Factor has to become setting or so. */
397 mi->factor = 0.01f;
398 mi->apply = InputTrackBall;
400 break;
403 t->helpline = HLP_HARROW;
404 break;
407 t->helpline = HLP_HARROW;
408 break;
411 t->helpline = HLP_VARROW;
412 break;
415 t->helpline = HLP_VARROW;
416 break;
419 t->helpline = HLP_CARROW;
420 break;
423 t->helpline = HLP_CARROW;
424 break;
425 case INPUT_ERROR:
426 mi->apply = nullptr;
427 t->helpline = HLP_ERROR;
428 break;
429 case INPUT_ERROR_DASH:
430 mi->apply = nullptr;
432 break;
433 case INPUT_NONE:
434 default:
435 mi->apply = nullptr;
436 break;
437 }
438
439 /* Setup for the mouse cursor: either set a custom one,
440 * or hide it if it will be drawn with the helpline. */
441 wmWindow *win = CTX_wm_window(t->context);
442 switch (t->helpline) {
443 case HLP_NONE:
444 /* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP. */
445 if (t->flag & T_MODAL) {
448 }
449 /* Only use special cursor, when tweaking strips with mouse. */
450 if (t->mode == TFM_SEQ_SLIDE) {
453 }
454 else {
456 if (sseq != nullptr) {
458 }
459 }
460 }
461
462 break;
463 case HLP_SPRING:
464 case HLP_ANGLE:
465 case HLP_TRACKBALL:
466 case HLP_HARROW:
467 case HLP_VARROW:
468 case HLP_CARROW:
469 if (t->flag & T_MODAL) {
472 }
473 break;
474 case HLP_ERROR:
475 case HLP_ERROR_DASH:
478 break;
479 default:
480 break;
481 }
482
483 /* If we've allocated new data, free the old data
484 * less hassle than checking before every alloc above. */
485 if (mi_data_prev && (mi_data_prev != mi->data)) {
486 MEM_freeN(mi_data_prev);
487 }
488}
489
490void setInputPostFct(MouseInput *mi, void (*post)(TransInfo *t, float values[3]))
491{
492 mi->post = post;
493}
494
495void applyMouseInput(TransInfo *t, MouseInput *mi, const float2 &mval, float output[3])
496{
497 double mval_db[2];
498
499 if (mi->use_virtual_mval) {
500 /* Update accumulator. */
501 double mval_delta[2];
502
503 mval_delta[0] = (mval[0] - mi->imval[0]) - mi->virtual_mval.prev[0];
504 mval_delta[1] = (mval[1] - mi->imval[1]) - mi->virtual_mval.prev[1];
505
506 mi->virtual_mval.prev[0] += mval_delta[0];
507 mi->virtual_mval.prev[1] += mval_delta[1];
508
509 if (mi->precision) {
510 mval_delta[0] *= double(mi->precision_factor);
511 mval_delta[1] *= double(mi->precision_factor);
512 }
513
514 mi->virtual_mval.accum[0] += mval_delta[0];
515 mi->virtual_mval.accum[1] += mval_delta[1];
516
517 mval_db[0] = mi->imval[0] + mi->virtual_mval.accum[0];
518 mval_db[1] = mi->imval[1] + mi->virtual_mval.accum[1];
519 }
520 else {
521 mval_db[0] = mval[0];
522 mval_db[1] = mval[1];
523 }
524
525 if (mi->apply != nullptr) {
526 mi->apply(t, mi, mval_db, output);
527 }
528
529 if (mi->post) {
530 mi->post(t, output);
531 }
532}
533
534void transform_input_update(TransInfo *t, const float fac)
535{
536 MouseInput *mi = &t->mouse;
537 float2 offset = fac * (mi->imval - mi->center);
538 mi->imval = t->center2d + offset;
539 mi->factor *= fac;
540
541 float center_old[2];
542 copy_v2_v2(center_old, mi->center);
543 copy_v2_v2(mi->center, t->center2d);
544
545 if (mi->use_virtual_mval) {
546 /* Update accumulator. */
547 double2 mval_delta;
548 sub_v2_v2v2_db(mval_delta, mi->virtual_mval.accum, mi->virtual_mval.prev);
549 mval_delta[0] *= fac;
550 mval_delta[1] *= fac;
552 mi->virtual_mval.accum += mval_delta;
553 }
554
556 float offset_center[2];
557 sub_v2_v2v2(offset_center, mi->center, center_old);
558 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
559 data->mval_prev[0] += offset_center[0];
560 data->mval_prev[1] += offset_center[1];
561 }
562
563 if (t->mode == TFM_EDGE_SLIDE) {
565 }
566 else if (t->mode == TFM_VERT_SLIDE) {
568 }
569}
570
572{
573 MouseInput *mi = &t->mouse;
575 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
576 data->angle = 0.0;
577 data->mval_prev[0] = mi->imval[0];
578 data->mval_prev[1] = mi->imval[1];
579 }
580 else {
581 memset(&mi->virtual_mval, 0, sizeof(mi->virtual_mval));
582 }
583}
584
586
587} // namespace blender::ed::transform
wmWindow * CTX_wm_window(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
#define BLI_ASSERT_UNIT_V2(v)
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float normalize_v2(float n[2])
MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
#define SWAP(type, a, b)
#define ELEM(...)
@ SEQ_RIGHTSEL
@ SEQ_LEFTSEL
@ SPACE_SEQ_DESELECT_STRIP_HANDLE
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
BMesh const char void * data
long long int int64_t
int64_t size() const
nullptr float
#define output
#define abs
float length(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
void transform_mode_vert_slide_reproject_input(TransInfo *t)
void transform_input_virtual_mval_reset(TransInfo *t)
static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float2 &dir)
static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
static void InputSpringDelta(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
static void InputCustomRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
void transform_input_reset(TransInfo *t, const float2 &mval)
void initMouseInput(TransInfo *t, MouseInput *mi, const float2 &center, const float2 &mval, bool precision)
static int transform_seq_slide_strip_cursor_get(const Strip *strip)
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
void setCustomPoints(TransInfo *t, MouseInput *mi, const int mval_start[2], const int mval_end[2])
bool transform_mode_edge_seq_slide_use_restore_handle_selection(const TransInfo *t)
static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
void setInputPostFct(MouseInput *mi, void(*post)(TransInfo *t, float values[3]))
static void InputTrackBall(TransInfo *, MouseInput *mi, const double mval[2], float output[3])
static void InputVector(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
static void InputCustomRatioFlip(TransInfo *, MouseInput *mi, const double mval[2], float output[3])
void applyMouseInput(TransInfo *t, MouseInput *mi, const float2 &mval, float output[3])
static void InputAngle(TransInfo *, MouseInput *mi, const double mval[2], float output[3])
static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
static void InputSpring(TransInfo *, MouseInput *mi, const double mval[2], float output[3])
void transform_input_update(TransInfo *t, const float fac)
static int transform_seq_slide_cursor_get(TransInfo *t)
static void calcSpringFactor(MouseInput *mi)
void transform_mode_edge_slide_reproject_input(TransInfo *t)
blender::VectorSet< Strip * > selected_strips_from_context(bContext *C)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
VecBase< double, 2 > double2
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
struct blender::ed::transform::MouseInput::@171313233360161344014275033122255027030213271133 virtual_mval
void(* apply)(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
Definition transform.hh:603
void(* post)(TransInfo *t, float values[3])
Definition transform.hh:604
transform modes used by different operators.
void WM_cursor_modal_set(wmWindow *win, int val)
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:52
@ WM_CURSOR_RIGHT_HANDLE
Definition wm_cursors.hh:65
@ WM_CURSOR_BOTH_HANDLES
Definition wm_cursors.hh:66
@ WM_CURSOR_LEFT_HANDLE
Definition wm_cursors.hh:64
@ WM_CURSOR_STOP
Definition wm_cursors.hh:18
@ WM_CURSOR_NONE
Definition wm_cursors.hh:59