Blender V4.5
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 if ((U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) == 0) {
312 }
313
314 const Scene *scene = t->scene;
316
317 if (strips.size() == 1) {
318 return transform_seq_slide_strip_cursor_get(strips[0]);
319 }
320 if (strips.size() == 2) {
321 Strip *strip1 = strips[0];
322 Strip *strip2 = strips[1];
323
324 if (seq::time_left_handle_frame_get(scene, strip1) >
325 seq::time_left_handle_frame_get(scene, strip2))
326 {
327 SWAP(Strip *, strip1, strip2);
328 }
329
330 if (strip1->channel != strip2->channel) {
332 }
333
334 if (seq::time_right_handle_frame_get(scene, strip1) !=
335 seq::time_left_handle_frame_get(scene, strip2))
336 {
338 }
339
340 const int cursor1 = transform_seq_slide_strip_cursor_get(strip1);
341 const int cursor2 = transform_seq_slide_strip_cursor_get(strip2);
342
343 if (cursor1 == WM_CURSOR_RIGHT_HANDLE && cursor2 == WM_CURSOR_LEFT_HANDLE) {
345 }
346 }
347
349}
350
352{
353 /* In case we allocate a new value. */
354 void *mi_data_prev = mi->data;
355
356 mi->use_virtual_mval = true;
357 mi->precision_factor = 1.0f / 10.0f;
358
359 switch (mode) {
360 case INPUT_VECTOR:
361 mi->apply = InputVector;
362 t->helpline = HLP_NONE;
363 break;
364 case INPUT_SPRING:
366 mi->apply = InputSpring;
367 t->helpline = HLP_SPRING;
368 break;
372 t->helpline = HLP_SPRING;
373 break;
377 t->helpline = HLP_SPRING;
378 break;
379 case INPUT_ANGLE:
380 case INPUT_ANGLE_SPRING: {
382 mi->use_virtual_mval = false;
383 mi->precision_factor = 1.0f / 30.0f;
384 data = MEM_callocN<InputAngle_Data>("angle accumulator");
385 data->mval_prev[0] = mi->imval[0];
386 data->mval_prev[1] = mi->imval[1];
387 mi->data = data;
388 if (mode == INPUT_ANGLE) {
389 mi->apply = InputAngle;
390 }
391 else {
394 }
395 t->helpline = HLP_ANGLE;
396 break;
397 }
398 case INPUT_TRACKBALL:
399 mi->precision_factor = 1.0f / 30.0f;
400 /* Factor has to become setting or so. */
401 mi->factor = 0.01f;
402 mi->apply = InputTrackBall;
404 break;
407 t->helpline = HLP_HARROW;
408 break;
411 t->helpline = HLP_HARROW;
412 break;
415 t->helpline = HLP_VARROW;
416 break;
419 t->helpline = HLP_VARROW;
420 break;
423 t->helpline = HLP_CARROW;
424 break;
427 t->helpline = HLP_CARROW;
428 break;
429 case INPUT_ERROR:
430 mi->apply = nullptr;
431 t->helpline = HLP_ERROR;
432 break;
433 case INPUT_ERROR_DASH:
434 mi->apply = nullptr;
436 break;
437 case INPUT_NONE:
438 default:
439 mi->apply = nullptr;
440 break;
441 }
442
443 /* Setup for the mouse cursor: either set a custom one,
444 * or hide it if it will be drawn with the helpline. */
445 wmWindow *win = CTX_wm_window(t->context);
446 switch (t->helpline) {
447 case HLP_NONE:
448 /* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP. */
449 if (t->flag & T_MODAL) {
452 }
453 /* Only use special cursor, when tweaking strips with mouse. */
454 if (t->mode == TFM_SEQ_SLIDE) {
457 }
458 else {
460 if (sseq != nullptr) {
462 }
463 }
464 }
465
466 break;
467 case HLP_SPRING:
468 case HLP_ANGLE:
469 case HLP_TRACKBALL:
470 case HLP_HARROW:
471 case HLP_VARROW:
472 case HLP_CARROW:
473 if (t->flag & T_MODAL) {
476 }
477 break;
478 case HLP_ERROR:
479 case HLP_ERROR_DASH:
482 break;
483 default:
484 break;
485 }
486
487 /* If we've allocated new data, free the old data
488 * less hassle than checking before every alloc above. */
489 if (mi_data_prev && (mi_data_prev != mi->data)) {
490 MEM_freeN(mi_data_prev);
491 }
492}
493
494void setInputPostFct(MouseInput *mi, void (*post)(TransInfo *t, float values[3]))
495{
496 mi->post = post;
497}
498
499void applyMouseInput(TransInfo *t, MouseInput *mi, const float2 &mval, float output[3])
500{
501 double mval_db[2];
502
503 if (mi->use_virtual_mval) {
504 /* Update accumulator. */
505 double mval_delta[2];
506
507 mval_delta[0] = (mval[0] - mi->imval[0]) - mi->virtual_mval.prev[0];
508 mval_delta[1] = (mval[1] - mi->imval[1]) - mi->virtual_mval.prev[1];
509
510 mi->virtual_mval.prev[0] += mval_delta[0];
511 mi->virtual_mval.prev[1] += mval_delta[1];
512
513 if (mi->precision) {
514 mval_delta[0] *= double(mi->precision_factor);
515 mval_delta[1] *= double(mi->precision_factor);
516 }
517
518 mi->virtual_mval.accum[0] += mval_delta[0];
519 mi->virtual_mval.accum[1] += mval_delta[1];
520
521 mval_db[0] = mi->imval[0] + mi->virtual_mval.accum[0];
522 mval_db[1] = mi->imval[1] + mi->virtual_mval.accum[1];
523 }
524 else {
525 mval_db[0] = mval[0];
526 mval_db[1] = mval[1];
527 }
528
529 if (mi->apply != nullptr) {
530 mi->apply(t, mi, mval_db, output);
531 }
532
533 if (mi->post) {
534 mi->post(t, output);
535 }
536}
537
538void transform_input_update(TransInfo *t, const float fac)
539{
540 MouseInput *mi = &t->mouse;
541 float2 offset = fac * (mi->imval - mi->center);
542 mi->imval = t->center2d + offset;
543 mi->factor *= fac;
544
545 float center_old[2];
546 copy_v2_v2(center_old, mi->center);
547 copy_v2_v2(mi->center, t->center2d);
548
549 if (mi->use_virtual_mval) {
550 /* Update accumulator. */
551 double2 mval_delta;
552 sub_v2_v2v2_db(mval_delta, mi->virtual_mval.accum, mi->virtual_mval.prev);
553 mval_delta[0] *= fac;
554 mval_delta[1] *= fac;
556 mi->virtual_mval.accum += mval_delta;
557 }
558
560 float offset_center[2];
561 sub_v2_v2v2(offset_center, mi->center, center_old);
562 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
563 data->mval_prev[0] += offset_center[0];
564 data->mval_prev[1] += offset_center[1];
565 }
566
567 if (t->mode == TFM_EDGE_SLIDE) {
569 }
570 else if (t->mode == TFM_VERT_SLIDE) {
572 }
573}
574
576{
577 MouseInput *mi = &t->mouse;
579 InputAngle_Data *data = static_cast<InputAngle_Data *>(mi->data);
580 data->angle = 0.0;
581 data->mval_prev[0] = mi->imval[0];
582 data->mval_prev[1] = mi->imval[1];
583 }
584 else {
585 memset(&mi->virtual_mval, 0, sizeof(mi->virtual_mval));
586 }
587}
588
590
591} // 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
@ USER_SEQ_ED_SIMPLE_TWEAKING
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
long long int int64_t
int64_t size() const
#define abs
#define output
float length(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
#define MEM_reallocN(vmemh, len)
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::@234026233207140165172274024151206225341251256216 virtual_mval
void(* apply)(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
Definition transform.hh:598
void(* post)(TransInfo *t, float values[3])
Definition transform.hh:599
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