Blender V4.5
view3d_navigate.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 "DNA_curve_types.h"
10
11#include "BLI_dial_2d.h"
12#include "BLI_listbase.h"
13#include "BLI_math_geom.h"
14#include "BLI_math_matrix.hh"
15#include "BLI_math_rotation.h"
16#include "BLI_math_vector.hh"
17#include "BLI_rect.h"
18
19#include "BKE_context.hh"
20#include "BKE_layer.hh"
21#include "BKE_object.hh"
22#include "BKE_paint.hh"
23#include "BKE_vfont.hh"
24
26
27#include "ED_screen.hh"
28#include "ED_transform.hh"
29
30#include "WM_api.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "view3d_intern.hh"
36
37#include "view3d_navigate.hh" /* own include */
38
39/* Prototypes. */
40static const ViewOpsType *view3d_navigation_type_from_idname(const char *idname);
41
43{
44 const bool use_select = (U.uiflag & USER_ORBIT_SELECTION) != 0;
45 const bool use_depth = (U.uiflag & USER_DEPTH_NAVIGATE) != 0;
46 const bool use_zoom_to_mouse = (U.uiflag & USER_ZOOM_TO_MOUSEPOS) != 0;
47
62
63 if (use_select) {
65 }
66 if (use_depth) {
68 }
69 if (use_zoom_to_mouse) {
71 }
72
73 return flag;
74}
75
76/* -------------------------------------------------------------------- */
79
81{
82 /* Store data. */
84 this->scene = CTX_data_scene(C);
85 this->area = CTX_wm_area(C);
86 this->region = CTX_wm_region(C);
87 this->v3d = static_cast<View3D *>(this->area->spacedata.first);
88 this->rv3d = static_cast<RegionView3D *>(this->region->regiondata);
89}
90
92{
93 copy_v3_v3(this->init.ofs, rv3d->ofs);
94 copy_v2_v2(this->init.ofs_lock, rv3d->ofs_lock);
95 this->init.camdx = rv3d->camdx;
96 this->init.camdy = rv3d->camdy;
97 this->init.camzoom = rv3d->camzoom;
98 this->init.dist = rv3d->dist;
99 copy_qt_qt(this->init.quat, rv3d->viewquat);
100
101 this->init.persp = rv3d->persp;
102 this->init.view = rv3d->view;
103 this->init.view_axis_roll = rv3d->view_axis_roll;
104}
105
107{
108 /* DOLLY, MOVE, ROTATE and ZOOM. */
109 {
110 /* For Move this only changes when offset is not locked. */
111 /* For Rotate this only changes when rotating around objects or last-brush. */
112 /* For Zoom this only changes when zooming to mouse position. */
113 /* Note this does not remove auto-keys on locked cameras. */
114 copy_v3_v3(this->rv3d->ofs, this->init.ofs);
115 }
116
117 /* MOVE and ZOOM. */
118 {
119 /* For Move this only changes when offset is not locked. */
120 /* For Zoom this only changes when zooming to mouse position in camera view. */
121 this->rv3d->camdx = this->init.camdx;
122 this->rv3d->camdy = this->init.camdy;
123 }
124
125 /* MOVE. */
126 {
127 if ((this->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(this->v3d, this->rv3d)) {
128 // this->rv3d->camdx = this->init.camdx;
129 // this->rv3d->camdy = this->init.camdy;
130 }
131 else if (ED_view3d_offset_lock_check(this->v3d, this->rv3d)) {
132 copy_v2_v2(this->rv3d->ofs_lock, this->init.ofs_lock);
133 }
134 else {
135 // copy_v3_v3(vod->rv3d->ofs, vod->init.ofs);
136 if (RV3D_LOCK_FLAGS(this->rv3d) & RV3D_BOXVIEW) {
137 view3d_boxview_sync(this->area, this->region);
138 }
139 }
140 }
141
142 /* ZOOM. */
143 {
144 this->rv3d->camzoom = this->init.camzoom;
145 }
146
147 /* ROTATE and ZOOM. */
148 {
149 /* For Rotate this only changes when orbiting from a camera view.
150 * In this case the `dist` is calculated based on the camera relative to the `ofs`. */
151
152 /* Note this does not remove auto-keys on locked cameras. */
153 this->rv3d->dist = this->init.dist;
154 }
155
156 /* ROLL and ROTATE. */
157 {
158 /* Note this does not remove auto-keys on locked cameras. */
159 copy_qt_qt(this->rv3d->viewquat, this->init.quat);
160 }
161
162 /* ROTATE. */
163 {
164 this->rv3d->persp = this->init.persp;
165 this->rv3d->view = this->init.view;
166 this->rv3d->view_axis_roll = this->init.view_axis_roll;
167 }
168
169 /* NOTE: there is no need to restore "last" values (as set by #ED_view3d_lastview_store). */
170
171 ED_view3d_camera_lock_sync(this->depsgraph, this->v3d, this->rv3d);
172}
173
175 Depsgraph *depsgraph,
176 ARegion *region,
177 View3D *v3d,
178 const wmEvent *event,
179 eViewOpsFlag viewops_flag,
180 const float dyn_ofs_override[3],
181 float r_pivot[3])
182{
183 if ((viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) && view3d_orbit_calc_center(C, r_pivot)) {
185 }
186
187 wmWindow *win = CTX_wm_window(C);
188
189 if (!(viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE)) {
191
192 /* Uses the `lastofs` in #view3d_orbit_calc_center. */
195 }
196
197 if (dyn_ofs_override) {
198 ED_view3d_win_to_3d_int(v3d, region, dyn_ofs_override, event->mval, r_pivot);
200 }
201
202 const bool use_depth_last = ED_view3d_autodist_last_check(win, event);
203
204 if (use_depth_last) {
205 ED_view3d_autodist_last_get(win, r_pivot);
206 }
207 else {
208 float fallback_depth_pt[3];
209 negate_v3_v3(fallback_depth_pt, static_cast<RegionView3D *>(region->regiondata)->ofs);
210
213 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, true, nullptr);
214 }
215
216 const bool is_set = ED_view3d_autodist(region, v3d, event->mval, r_pivot, fallback_depth_pt);
217
218 ED_view3d_autodist_last_set(win, event, r_pivot, is_set);
219 }
220
222}
223
225 const wmEvent *event,
226 const ViewOpsType *nav_type,
227 const float dyn_ofs_override[3],
228 const bool use_cursor_init)
229{
230 using namespace blender;
231 this->nav_type = nav_type;
233
234 if (!use_cursor_init) {
236 }
237
238 bool calc_rv3d_dist = true;
239#ifdef WITH_INPUT_NDOF
240 if (ELEM(nav_type,
241 &ViewOpsType_ndof_orbit,
242 &ViewOpsType_ndof_orbit_zoom,
243 &ViewOpsType_ndof_pan,
244 &ViewOpsType_ndof_all))
245 {
246 calc_rv3d_dist = false;
247
248 /* When using "Free" NDOF navigation, ignore "Orbit Around Selected" preference.
249 * Logically it doesn't make sense to use the selection as a pivot when the first-person
250 * navigation pivots from the view-point. This also interferes with zoom-speed,
251 * causing zoom-speed scale based on the distance to the selection center, see: #115253. */
252 if (U.ndof_navigation_mode == NDOF_NAVIGATION_MODE_FLY) {
254 }
255 }
256#endif
257
258 /* Set the view from the camera, if view locking is enabled.
259 * we may want to make this optional but for now its needed always. */
261
262 this->state_backup();
263
264 if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
265 if (ED_view3d_persp_ensure(depsgraph, this->v3d, this->region)) {
266 /* If we're switching from camera view to the perspective one,
267 * need to tag viewport update, so camera view and borders are properly updated. */
269 }
270 }
271
273 float pivot_new[3];
274 eViewOpsFlag pivot_type = navigate_pivot_get(
275 C, depsgraph, region, v3d, event, viewops_flag, dyn_ofs_override, pivot_new);
276
278 viewops_flag |= pivot_type;
279
280 negate_v3_v3(this->dyn_ofs, pivot_new);
281 this->use_dyn_ofs = true;
282
283 if (pivot_type == VIEWOPS_FLAG_DEPTH_NAVIGATE) {
284 /* Ensure we'll always be able to zoom into the new pivot point and panning won't go bad when
285 * dist is zero. Therefore, set a new #RegionView3D::ofs and #RegionView3D::dist so that the
286 * dist value becomes the distance from the new pivot point. */
287
288 if (rv3d->is_persp) {
289 float my_origin[3]; /* Original #RegionView3D.ofs. */
290 float my_pivot[3]; /* View pivot. */
291 float dvec[3];
292
293 negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
294
295 /* remove dist value */
296 float3 upvec;
297 upvec[0] = upvec[1] = 0;
298 upvec[2] = rv3d->dist;
299 float3x3 mat = float3x3(float4x4(rv3d->viewinv));
300
301 upvec = math::transform_point(mat, upvec);
302 add_v3_v3v3(my_pivot, my_origin, upvec);
303
304 /* find a new ofs value that is along the view axis
305 * (rather than the mouse location) */
306 float lambda = closest_to_line_v3(dvec, pivot_new, my_pivot, my_origin);
307
308 negate_v3_v3(rv3d->ofs, dvec);
309 rv3d->dist = len_v3v3(my_pivot, dvec);
310
311 if (lambda < 0.0f) {
312 /* The distance is actually negative. */
313 rv3d->dist *= -1;
314 }
315 }
316 else {
317 const float mval_region_mid[2] = {float(region->winx) / 2.0f, float(region->winy) / 2.0f};
318 ED_view3d_win_to_3d(v3d, region, pivot_new, mval_region_mid, rv3d->ofs);
319 negate_v3(rv3d->ofs);
320 }
321 }
322
323 /* Reinitialize `this->init.dist` and `this->init.ofs` as these values may have changed
324 * when #ED_view3d_persp_ensure was called or when the operator uses `Auto Depth`.
325 *
326 * XXX: The initial state captured by #ViewOpsData::state_backup is being modified here.
327 * This causes the state not to be fully restored when canceling a navigation operation. */
328 this->init.dist = rv3d->dist;
329 copy_v3_v3(this->init.ofs, rv3d->ofs);
330 }
331
333 float tvec[3];
334 negate_v3_v3(tvec, rv3d->ofs);
335 this->init.zfac = ED_view3d_calc_zfac(rv3d, tvec);
336 }
337
338 this->init.persp_with_auto_persp_applied = rv3d->persp;
339
340 if (event) {
341 this->init.event_type = event->type;
342 copy_v2_v2_int(this->init.event_xy, event->xy);
343 copy_v2_v2_int(this->prev.event_xy, event->xy);
344
345 if (use_cursor_init) {
346 zero_v2_int(this->init.event_xy_offset);
347 }
348 else {
349 /* Simulate the event starting in the middle of the region. */
350 this->init.event_xy_offset[0] = BLI_rcti_cent_x(&this->region->winrct) - event->xy[0];
351 this->init.event_xy_offset[1] = BLI_rcti_cent_y(&this->region->winrct) - event->xy[1];
352 }
353
354 /* For dolly */
355 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
356 ED_view3d_win_to_vector(region, mval, this->init.mousevec);
357
358 {
359 int2 event_xy_offset = int2(event->xy) + this->init.event_xy_offset;
360
361 /* For rotation with trackball rotation. */
362 calctrackballvec(&region->winrct, event_xy_offset, this->init.trackvec);
363 }
364 }
365
366 copy_qt_qt(this->curr.viewquat, rv3d->viewquat);
367
368 this->reverse = 1.0f;
369 if (rv3d->persmat[2][1] < 0.0f) {
370 this->reverse = -1.0f;
371 }
372
373 this->viewops_flag = viewops_flag;
374
375 /* Default. */
376 this->use_dyn_ofs_ortho_correction = false;
377
378 rv3d->rflag |= RV3D_NAVIGATING;
379}
380
382{
383 this->rv3d->rflag &= ~RV3D_NAVIGATING;
384
385 if (this->timer) {
386 WM_event_timer_remove(CTX_wm_manager(C), this->timer->win, this->timer);
387 }
388
389 if (this->init.dial) {
390 BLI_dial_free(this->init.dial);
391 this->init.dial = nullptr;
392 }
393
394 /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw
395 * faster while navigation operator runs. */
397}
398
400
401/* -------------------------------------------------------------------- */
404
405/* Used for navigation utility in operators. */
407 /* To track only the navigation #wmKeyMapItem items and allow changes to them, an internal
408 * #wmKeyMap is created with their copy. */
410
411 /* Used by #ED_view3d_navigation_do. */
412 bool is_modal_event = false;
413
414 ViewOpsData_Utility(bContext *C, const wmKeyMapItem *kmi_merge = nullptr)
416 {
417 this->init_context(C);
418
421
423
424 wmKeyMap keymap_tmp = {};
425
426 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
427 if (!STRPREFIX(kmi->idname, "VIEW3D")) {
428 continue;
429 }
430 if (kmi->flag & KMI_INACTIVE) {
431 continue;
432 }
433 if (view3d_navigation_type_from_idname(kmi->idname) == nullptr) {
434 continue;
435 }
436
437 wmKeyMapItem *kmi_cpy = WM_keymap_add_item_copy(&keymap_tmp, kmi);
438 if (kmi_merge) {
439 if (kmi_merge->shift == KM_MOD_HELD ||
440 ELEM(kmi_merge->type, EVT_RIGHTSHIFTKEY, EVT_LEFTSHIFTKEY))
441 {
442 kmi_cpy->shift = KM_MOD_HELD;
443 }
444 if (kmi_merge->ctrl == KM_MOD_HELD ||
445 ELEM(kmi_merge->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY))
446 {
447 kmi_cpy->ctrl = KM_MOD_HELD;
448 }
449 if (kmi_merge->alt == KM_MOD_HELD ||
450 ELEM(kmi_merge->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY))
451 {
452 kmi_cpy->alt = KM_MOD_HELD;
453 }
454 if (kmi_merge->oskey == KM_MOD_HELD || ELEM(kmi_merge->type, EVT_OSKEY)) {
455 kmi_cpy->oskey = KM_MOD_HELD;
456 }
457 if (kmi_merge->hyper == KM_MOD_HELD || ELEM(kmi_merge->type, EVT_HYPER)) {
458 kmi_cpy->hyper = KM_MOD_HELD;
459 }
460 if (!ISKEYMODIFIER(kmi_merge->type)) {
461 kmi_cpy->keymodifier = kmi_merge->type;
462 }
463 }
464 }
465
466 /* Weak, but only the keymap items from the #wmKeyMap struct are needed here. */
467 this->keymap_items = keymap_tmp.items;
468
470 }
471
473 {
474 /* Weak, but rebuild the struct #wmKeyMap to clear the keymap items. */
476
477 wmKeyMap keymap_tmp = {};
478 keymap_tmp.items = this->keymap_items;
479 WM_keymap_clear(&keymap_tmp);
480
482 }
483
484 MEM_CXX_CLASS_ALLOC_FUNCS("ViewOpsData_Utility")
485};
486
487static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
488{
490 return false;
491 }
492
493 const RegionView3D *rv3d = CTX_wm_region_view3d(C);
494 return !(RV3D_LOCK_FLAGS(rv3d) & viewlock);
495}
496
498{
499 if (event->type == EVT_MODAL_MAP) {
500 switch (event->val) {
502 return VIEW_CANCEL;
504 return VIEW_CONFIRM;
506 vod->axis_snap = true;
507 return VIEW_APPLY;
510 vod->axis_snap = false;
511 return VIEW_APPLY;
515 const ViewOpsType *nav_type_new = (event->val == VIEWROT_MODAL_SWITCH_ZOOM) ?
517 (event->val == VIEWROT_MODAL_SWITCH_MOVE) ?
520 if (nav_type_new == vod->nav_type) {
521 break;
522 }
523 vod->nav_type = nav_type_new;
524 return VIEW_APPLY;
525 }
526 }
527 }
528 else {
529 if (event->type == TIMER && event->customdata == vod->timer) {
530 /* Zoom uses timer for continuous zoom. */
531 return VIEW_APPLY;
532 }
533 if (event->type == MOUSEMOVE) {
534 return VIEW_APPLY;
535 }
536 if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
537 return VIEW_CONFIRM;
538 }
539 if (event->type == EVT_ESCKEY && event->val == KM_PRESS) {
540 return VIEW_CANCEL;
541 }
542 }
543
544 return VIEW_PASS;
545}
546
548 ViewOpsData *vod,
549 const wmEvent *event,
551 const ViewOpsType *nav_type,
552 const float dyn_ofs_override[3])
553{
554 if (!nav_type->init_fn) {
555 return OPERATOR_CANCELLED;
556 }
557
558 bool use_cursor_init = false;
559 if (PropertyRNA *prop = RNA_struct_find_property(ptr, "use_cursor_init")) {
560 use_cursor_init = RNA_property_boolean_get(ptr, prop);
561 }
562
563 vod->init_navigation(C, event, nav_type, dyn_ofs_override, use_cursor_init);
565
566 return nav_type->init_fn(C, vod, event, ptr);
567}
568
570 wmOperator *op,
571 const wmEvent *event,
572 const ViewOpsType *nav_type)
573{
574 ViewOpsData *vod = new ViewOpsData();
575 vod->init_context(C);
577 C, vod, event, op->ptr, nav_type, nullptr);
578 op->customdata = (void *)vod;
579
583 }
584
585 viewops_data_free(C, vod);
586 op->customdata = nullptr;
587 return ret;
588}
589
591
592/* -------------------------------------------------------------------- */
595
600
605
610
612{
613 /* This combination of flags is needed for the dolly operator,
614 * see code-comments there for details. */
616}
617
619{
620 ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
621
622 const ViewOpsType *nav_type_prev = vod->nav_type;
623 const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
624 if (nav_type_prev != vod->nav_type) {
625 wmOperatorType *ot_new = WM_operatortype_find(vod->nav_type->idname, false);
626 WM_operator_type_set(op, ot_new);
627 vod->end_navigation(C);
628 return view3d_navigation_invoke_generic(C, vod, event, op->ptr, vod->nav_type, nullptr);
629 }
630
631 wmOperatorStatus ret = vod->nav_type->apply_fn(C, vod, event_code, event->xy);
632
633 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
634 if (ret & OPERATOR_FINISHED) {
636 }
637 viewops_data_free(C, vod);
638 op->customdata = nullptr;
639 }
640
641 return ret;
642}
643
645{
646 viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
647 op->customdata = nullptr;
648}
649
651
652/* -------------------------------------------------------------------- */
655
657{
659 PropertyRNA *prop;
660 prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX);
662 prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX);
664 }
665 if (flag & V3D_OP_PROP_DELTA) {
666 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
667 }
669 PropertyRNA *prop;
670 prop = RNA_def_boolean(
671 ot->srna, "use_all_regions", false, "All Regions", "View selected for all regions");
673 }
676 }
677}
678
680
681/* -------------------------------------------------------------------- */
684
685void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3])
686{
687 const float radius = V3D_OP_TRACKBALLSIZE;
688 const float t = radius / float(M_SQRT2);
689 const float size[2] = {float(BLI_rcti_size_x(rect)), float(BLI_rcti_size_y(rect))};
690 /* Aspect correct so dragging in a non-square view doesn't squash the direction.
691 * So diagonal motion rotates the same direction the cursor is moving. */
692 const float size_min = min_ff(size[0], size[1]);
693 const float aspect[2] = {size_min / size[0], size_min / size[1]};
694
695 /* Normalize x and y. */
696 r_dir[0] = (event_xy[0] - BLI_rcti_cent_x(rect)) / ((size[0] * aspect[0]) / 2.0);
697 r_dir[1] = (event_xy[1] - BLI_rcti_cent_y(rect)) / ((size[1] * aspect[1]) / 2.0);
698 const float d = len_v2(r_dir);
699 if (d < t) {
700 /* Inside sphere. */
701 r_dir[2] = sqrtf(square_f(radius) - square_f(d));
702 }
703 else {
704 /* On hyperbola. */
705 r_dir[2] = square_f(t) / d;
706 }
707}
708
709void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
710 const float ofs_old[3],
711 const float viewquat_old[4],
712 const float viewquat_new[4],
713 const float dyn_ofs[3])
714{
715 float q[4];
716 invert_qt_qt_normalized(q, viewquat_old);
717 mul_qt_qtqt(q, q, viewquat_new);
718
720
721 sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs);
722 mul_qt_v3(q, r_ofs);
723 add_v3_v3(r_ofs, dyn_ofs);
724}
725
727 const float viewquat_old[4],
728 const float viewquat_new[4],
729 const float dyn_ofs[3])
730{
731 /* NOTE(@ideasman42): While orbiting in orthographic mode the "depth" of the offset
732 * (position along the views Z-axis) is only noticeable when the view contents is clipped.
733 * The likelihood of clipping depends on the clipping range & size of the scene.
734 * In practice some users might not run into this, however using dynamic-offset in
735 * orthographic views can cause the depth of the offset to drift while navigating the view,
736 * causing unexpected clipping that seems like a bug from the user perspective, see: #104385.
737 *
738 * Imagine a camera is focused on a distant object. Now imagine a closer object in front of
739 * the camera is used as a pivot, the camera is rotated to view it from the side (~90d rotation).
740 * The outcome is the camera is now focused on a distant region to the left/right.
741 * The new focal point is unlikely to point to anything useful (unless by accident).
742 * Instead of a focal point - the `rv3d->ofs` is being manipulated in this case.
743 *
744 * Resolve by moving #RegionView3D::ofs so it is depth-aligned to `dyn_ofs`,
745 * this is interpolated by the amount of rotation so minor rotations don't cause
746 * the view-clipping to suddenly jump.
747 *
748 * Perspective Views
749 * =================
750 *
751 * This logic could also be applied to perspective views because the issue of the `ofs`
752 * being a location which isn't useful exists there too, however the problem where this location
753 * impacts the clipping does *not* exist, as the clipping range starts from the view-point
754 * (`ofs` + `dist` along the view Z-axis) unlike orthographic views which center around `ofs`.
755 * Nevertheless there will be cases when having `ofs` and a large `dist` pointing nowhere doesn't
756 * give ideal behavior (zooming may jump in larger than expected steps and panning the view may
757 * move too much in relation to nearby objects - for example). So it's worth investigating but
758 * should be done with extra care as changing `ofs` in perspective view also requires changing
759 * the `dist` which could cause unexpected results if the calculated `dist` happens to be small.
760 * So disable this workaround in perspective view unless there are clear benefits to enabling. */
761
762 float q_inv[4];
763
764 float view_z_init[3] = {0.0f, 0.0f, 1.0f};
765 invert_qt_qt_normalized(q_inv, viewquat_old);
766 mul_qt_v3(q_inv, view_z_init);
767
768 float view_z_curr[3] = {0.0f, 0.0f, 1.0f};
769 invert_qt_qt_normalized(q_inv, viewquat_new);
770 mul_qt_v3(q_inv, view_z_curr);
771
772 const float angle_cos = max_ff(0.0f, dot_v3v3(view_z_init, view_z_curr));
773 /* 1.0 or more means no rotation, there is nothing to do in that case. */
774 if (LIKELY(angle_cos < 1.0f)) {
775 const float dot_ofs_curr = dot_v3v3(view_z_curr, ofs);
776 const float dot_ofs_next = dot_v3v3(view_z_curr, dyn_ofs);
777 const float ofs_delta = dot_ofs_next - dot_ofs_curr;
778 if (LIKELY(ofs_delta != 0.0f)) {
779 /* Calculate a factor where 0.0 represents no rotation and 1.0 represents 90d or more.
780 * NOTE: Without applying the factor, the distances immediately changes
781 * (useful for testing), but not good for the users experience as minor rotations
782 * should not immediately adjust the depth. */
783 const float factor = acosf(angle_cos) / M_PI_2;
784 madd_v3_v3fl(ofs, view_z_curr, ofs_delta * factor);
785 }
786 }
787}
788
789void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
790{
791 if (vod->use_dyn_ofs) {
792 RegionView3D *rv3d = vod->rv3d;
794 rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
795
798 rv3d->ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
799 }
800 }
801}
802
803bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
804{
805 using namespace blender;
806 static float3 lastofs = float3(0);
807 bool is_set = false;
808
810 Scene *scene = CTX_data_scene(C);
813 View3D *v3d = CTX_wm_view3d(C);
814 BKE_view_layer_synced_ensure(scene_eval, view_layer_eval);
815 Object *ob_act_eval = BKE_view_layer_active_object_get(view_layer_eval);
816 Object *ob_act = DEG_get_original(ob_act_eval);
817
818 if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
819 /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
820 ((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0)
821 {
822 BKE_paint_stroke_get_average(scene, ob_act_eval, lastofs);
823 is_set = true;
824 }
825 else if (ob_act && ELEM(ob_act->mode,
831 {
832 BKE_paint_stroke_get_average(scene, ob_act_eval, lastofs);
833 is_set = true;
834 }
835 else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
836 Curve *cu = static_cast<Curve *>(ob_act_eval->data);
837 EditFont *ef = cu->editfont;
838
839 lastofs = float3(0);
840 for (int i = 0; i < 4; i++) {
841 lastofs += ef->textcurs[i];
842 }
843 lastofs *= 0.25f;
844
845 lastofs = math::transform_point(ob_act_eval->object_to_world(), lastofs);
846
847 is_set = true;
848 }
849 else if (ob_act == nullptr || ob_act->mode == OB_MODE_OBJECT) {
850 /* Object mode uses bounding-box centers. */
851 int total = 0;
852 float3 select_center(0);
853
854 zero_v3(select_center);
855 LISTBASE_FOREACH (const Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
856 if (BASE_SELECTED(v3d, base_eval)) {
857 /* Use the bounding-box if we can. */
858 const Object *ob_eval = base_eval->object;
859
860 if (const std::optional<Bounds<float3>> bounds = BKE_object_boundbox_get(ob_eval)) {
861 const float3 center = math::midpoint(bounds->min, bounds->max);
862 select_center += math::transform_point(ob_eval->object_to_world(), center);
863 }
864 else {
865 add_v3_v3(select_center, ob_eval->object_to_world().location());
866 }
867 total++;
868 }
869 }
870 if (total) {
871 mul_v3_fl(select_center, 1.0f / float(total));
872 copy_v3_v3(lastofs, select_center);
873 is_set = true;
874 }
875 }
876 else {
877 /* If there's no selection, `lastofs` is unmodified and last value since static. */
879 }
880
881 copy_v3_v3(r_dyn_ofs, lastofs);
882
883 return is_set;
884}
885
887 const wmEvent *event,
888 const ViewOpsType *nav_type,
889 const bool use_cursor_init)
890{
891 ViewOpsData *vod = new ViewOpsData();
892 vod->init_context(C);
893 vod->init_navigation(C, event, nav_type, nullptr, use_cursor_init);
894 return vod;
895}
896
898{
899 if (!vod) {
900 return;
901 }
902 vod->end_navigation(C);
903 delete vod;
904}
905
907
908/* -------------------------------------------------------------------- */
911
913 View3D *v3d,
914 ARegion *region,
915 const float quat_[4],
916 char view,
917 char view_axis_roll,
918 int perspo,
919 const float *align_to_quat,
920 const int smooth_viewtx)
921{
922 /* no nullptr check is needed, poll checks */
923 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
924
925 float quat[4];
926 const short orig_persp = rv3d->persp;
927 const char orig_view = rv3d->view;
928 const char orig_view_axis_roll = rv3d->view_axis_roll;
929
930 normalize_qt_qt(quat, quat_);
931
932 if (align_to_quat) {
933 mul_qt_qtqt(quat, quat, align_to_quat);
934 rv3d->view = view = RV3D_VIEW_USER;
936 }
937 else {
938 rv3d->view = view;
939 rv3d->view_axis_roll = view_axis_roll;
940 }
941
942 /* Redrawing when changes are detected is needed because the current view
943 * orientation may be a "User" view that matches the axis exactly.
944 * In this case smooth-view exits early as no view transition is needed.
945 * However, changing the view must redraw the region as it changes the
946 * viewport name & grid drawing. */
947 if ((rv3d->view != orig_view) || (rv3d->view_axis_roll != orig_view_axis_roll)) {
948 ED_region_tag_redraw(region);
949 }
950
952 return;
953 }
954
955 if (U.uiflag & USER_AUTOPERSP) {
956 rv3d->persp = RV3D_VIEW_IS_AXIS(view) ? RV3D_ORTHO : perspo;
957 }
958 else if (rv3d->persp == RV3D_CAMOB) {
959 rv3d->persp = perspo;
960 }
961 if (rv3d->persp != orig_persp) {
962 ED_region_tag_redraw(region);
963 }
964
965 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
966 /* to camera */
967 V3D_SmoothParams sview = {nullptr};
968 sview.camera_old = v3d->camera;
969 sview.ofs = rv3d->ofs;
970 sview.quat = quat;
971 /* No undo because this switches to/from camera. */
972 sview.undo_str = nullptr;
973
974 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
975 }
976 else if (orig_persp == RV3D_CAMOB && v3d->camera) {
977 /* from camera */
978 float ofs[3], dist;
979
980 copy_v3_v3(ofs, rv3d->ofs);
981 dist = rv3d->dist;
982
983 /* so we animate _from_ the camera location */
985 ED_view3d_from_object(camera_eval, rv3d->ofs, nullptr, &rv3d->dist, nullptr);
986
987 V3D_SmoothParams sview = {nullptr};
988 sview.camera_old = camera_eval;
989 sview.ofs = ofs;
990 sview.quat = quat;
991 sview.dist = &dist;
992 /* No undo because this switches to/from camera. */
993 sview.undo_str = nullptr;
994
995 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
996 }
997 else {
998 /* rotate around selection */
999 const float *dyn_ofs_pt = nullptr;
1000 float dyn_ofs[3];
1001
1002 if (U.uiflag & USER_ORBIT_SELECTION) {
1003 if (view3d_orbit_calc_center(C, dyn_ofs)) {
1004 negate_v3(dyn_ofs);
1005 dyn_ofs_pt = dyn_ofs;
1006 }
1007 }
1008
1009 /* no camera involved */
1010 V3D_SmoothParams sview = {nullptr};
1011 sview.quat = quat;
1012 sview.dyn_ofs = dyn_ofs_pt;
1013 /* No undo because this switches to/from camera. */
1014 sview.undo_str = nullptr;
1015
1016 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
1017 }
1018}
1019
1020void viewmove_apply(ViewOpsData *vod, int x, int y)
1021{
1022 const float event_ofs[2] = {
1023 float(vod->prev.event_xy[0] - x),
1024 float(vod->prev.event_xy[1] - y),
1025 };
1026
1027 if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
1028 ED_view3d_camera_view_pan(vod->region, event_ofs);
1029 }
1030 else if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) {
1031 vod->rv3d->ofs_lock[0] -= (event_ofs[0] * 2.0f) / float(vod->region->winx);
1032 vod->rv3d->ofs_lock[1] -= (event_ofs[1] * 2.0f) / float(vod->region->winy);
1033 }
1034 else {
1035 float dvec[3];
1036
1037 ED_view3d_win_to_delta(vod->region, event_ofs, vod->init.zfac, dvec);
1038
1039 sub_v3_v3(vod->rv3d->ofs, dvec);
1040
1041 if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
1042 view3d_boxview_sync(vod->area, vod->region);
1043 }
1044 }
1045
1046 vod->prev.event_xy[0] = x;
1047 vod->prev.event_xy[1] = y;
1048
1049 ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
1050
1052}
1053
1055
1056/* -------------------------------------------------------------------- */
1059
1060/* Detect the navigation operation, by the name of the navigation operator (obtained by
1061 * `wmKeyMapItem::idname`) */
1062static const ViewOpsType *view3d_navigation_type_from_idname(const char *idname)
1063{
1064 const blender::Array<const ViewOpsType *> nav_types = {
1069// &ViewOpsType_orbit,
1070// &ViewOpsType_roll,
1071// &ViewOpsType_dolly,
1072#ifdef WITH_INPUT_NDOF
1073 &ViewOpsType_ndof_orbit,
1074 &ViewOpsType_ndof_orbit_zoom,
1075 &ViewOpsType_ndof_pan,
1076 &ViewOpsType_ndof_all,
1077#endif
1078 };
1079
1080 const char *op_name = idname + sizeof("VIEW3D_OT_");
1081 for (const ViewOpsType *nav_type : nav_types) {
1082 if (STREQ(op_name, nav_type->idname + sizeof("VIEW3D_OT_"))) {
1083 return nav_type;
1084 }
1085 }
1086 return nullptr;
1087}
1088
1090{
1091 /* Unlike `viewops_data_create`, `ED_view3d_navigation_init` creates a navigation context along
1092 * with an array of `wmKeyMapItem`s used for navigation. */
1093 if (!CTX_wm_region_view3d(C)) {
1094 return nullptr;
1095 }
1096
1097 return new ViewOpsData_Utility(C, kmi_merge);
1098}
1099
1101 ViewOpsData *vod,
1102 const wmEvent *event,
1103 const float depth_loc_override[3])
1104{
1105 if (!vod) {
1106 return false;
1107 }
1108
1109 wmEvent event_tmp;
1110 if (event->type == EVT_MODAL_MAP) {
1111 /* Workaround to use the original event values. */
1112 event_tmp = *event;
1113 event_tmp.type = event->prev_type;
1114 event_tmp.val = event->prev_val;
1115 event = &event_tmp;
1116 }
1117
1119
1120 ViewOpsData_Utility *vod_intern = static_cast<ViewOpsData_Utility *>(vod);
1121 if (vod_intern->is_modal_event) {
1122 const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
1123 op_return = vod->nav_type->apply_fn(C, vod, event_code, event->xy);
1124 if (op_return != OPERATOR_RUNNING_MODAL) {
1125 vod->end_navigation(C);
1126 vod_intern->is_modal_event = false;
1127 }
1128 }
1129 else {
1130 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &vod_intern->keymap_items) {
1131 if (!WM_event_match(event, kmi)) {
1132 continue;
1133 }
1134
1135 const ViewOpsType *nav_type = view3d_navigation_type_from_idname(kmi->idname);
1136 if (nav_type->poll_fn && !nav_type->poll_fn(C)) {
1137 break;
1138 }
1139
1141 C, vod, event, kmi->ptr, nav_type, depth_loc_override);
1142
1143 if (op_return == OPERATOR_RUNNING_MODAL) {
1144 vod_intern->is_modal_event = true;
1145 }
1146 else {
1147 vod->end_navigation(C);
1148 /* Postpone the navigation confirmation to the next call.
1149 * This avoids constant updating of the transform operation for example. */
1150 vod->rv3d->rflag |= RV3D_NAVIGATING;
1151 }
1152 break;
1153 }
1154 }
1155
1156 if (op_return != OPERATOR_CANCELLED) {
1157 /* Although #ED_view3d_update_viewmat is already called when redrawing the 3D View, do it here
1158 * as well, so the updated matrix values can be accessed by the operator. */
1160 vod->depsgraph, vod->scene, vod->v3d, vod->region, nullptr, nullptr, nullptr, false);
1161
1162 return true;
1163 }
1164 if (vod->rv3d->rflag & RV3D_NAVIGATING) {
1165 /* Add a fake confirmation. */
1166 vod->rv3d->rflag &= ~RV3D_NAVIGATING;
1167 return true;
1168 }
1169
1170 return false;
1171}
1172
1174{
1175 ViewOpsData_Utility *vod_intern = static_cast<ViewOpsData_Utility *>(vod);
1176 vod_intern->end_navigation(C);
1177 delete vod_intern;
1178}
1179
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
Object * BKE_object_pose_armature_get(Object *ob)
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
void BKE_paint_stroke_get_average(const Scene *scene, const Object *ob, float stroke[3])
Definition paint.cc:1841
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_dial_free(Dial *dial)
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE float square_f(float a)
#define M_SQRT2
#define M_PI_2
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
void invert_qt_normalized(float q[4])
void mul_qt_v3(const float q[4], float r[3])
float normalize_qt_qt(float r[4], const float q[4])
void invert_qt_qt_normalized(float q1[4], const float q2[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:177
#define STRPREFIX(a, b)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ViewLayer * DEG_get_evaluated_view_layer(const Depsgraph *graph)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
#define OB_MODE_ALL_PAINT
@ OB_MODE_VERTEX_GREASE_PENCIL
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT_CURVES
@ OB_MODE_PAINT_GREASE_PENCIL
@ OB_MODE_SCULPT_GREASE_PENCIL
@ OB_MODE_OBJECT
@ OB_MODE_WEIGHT_GREASE_PENCIL
@ OB_FONT
#define BASE_SELECTED(v3d, base)
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ USER_ORBIT_SELECTION
@ USER_AUTOPERSP
@ USER_ZOOM_TO_MOUSEPOS
@ USER_DEPTH_NAVIGATE
@ NDOF_NAVIGATION_MODE_FLY
#define RV3D_VIEW_IS_AXIS(view)
@ RV3D_CAMOB
@ RV3D_ORTHO
@ RV3D_VIEW_AXIS_ROLL_0
#define RV3D_LOCK_FLAGS(rv3d)
@ V3D_AROUND_CENTER_MEDIAN
@ RV3D_LOCK_ROTATION
@ RV3D_LOCK_LOCATION
@ RV3D_LOCK_ZOOM_AND_DOLLY
@ RV3D_BOXVIEW
@ RV3D_VIEW_USER
@ RV3D_NAVIGATING
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
bool ED_operator_region_view3d_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
void ED_view3d_depth_override(Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obact, eV3DDepthOverrideMode mode, bool use_overlay, ViewDepths **r_depths)
void ED_view3d_win_to_3d_int(const View3D *v3d, const ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
void ED_view3d_autodist_last_clear(wmWindow *win)
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
bool ED_view3d_autodist_last_check(wmWindow *win, const wmEvent *event)
void ED_view3d_autodist_last_set(wmWindow *win, const wmEvent *event, const float ofs[3], const bool has_depth)
void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], const float *dist, float *lens)
bool ED_view3d_autodist(ARegion *region, View3D *v3d, const int mval[2], float mouse_worldloc[3], const float fallback_depth_pt[3])
bool ED_view3d_has_depth_buffer_updated(const Depsgraph *depsgraph, const View3D *v3d)
bool ED_view3d_autodist_last_get(wmWindow *win, float r_ofs[3])
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, bool calc_dist)
bool ED_view3d_camera_view_pan(ARegion *region, const float event_ofs[2])
bool ED_view3d_camera_lock_undo_push(const char *str, const View3D *v3d, const RegionView3D *rv3d, bContext *C)
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
@ V3D_DEPTH_NO_GPENCIL
Definition ED_view3d.hh:192
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float r_out[3])
void ED_view3d_update_viewmat(const Depsgraph *depsgraph, const Scene *scene, View3D *v3d, ARegion *region, const float viewmat[4][4], const float winmat[4][4], const rcti *rect, bool offscreen)
static AppView * view
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
@ KM_PRESS
Definition WM_types.hh:308
@ KM_RELEASE
Definition WM_types.hh:309
#define KM_MOD_HELD
Definition WM_types.hh:323
#define U
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
#define acosf(x)
#define sqrtf(x)
VecBase< int, 2 > int2
#define this
MatBase< 4, 4 > float4x4
VecBase< float, 3 > float3
MatBase< 3, 3 > float3x3
@ VIEW_CONFIRM
Definition image_ops.cc:600
@ VIEW_PASS
Definition image_ops.cc:598
@ VIEW_APPLY
Definition image_ops.cc:599
MINLINE void zero_v2_int(int r[2])
bool calc_pivot_pos(const bContext *C, const short pivot_type, float r_pivot_pos[3])
T midpoint(const T &a, const T &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
return ret
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
void * regiondata
struct EditFont * editfont
float textcurs[4][2]
Definition BKE_vfont.hh:48
const char * undo_str
const float * dyn_ofs
struct Object * camera
ViewOpsData_Utility(bContext *C, const wmKeyMapItem *kmi_merge=nullptr)
struct ViewOpsData::@141137043204146177164264012027050363252044307207 curr
const ViewOpsType * nav_type
char persp_with_auto_persp_applied
void end_navigation(bContext *C)
eViewOpsFlag viewops_flag
bool use_dyn_ofs_ortho_correction
Depsgraph * depsgraph
blender::int2 event_xy
struct ViewOpsData::@344100303242340012120345311345005106217257322066 prev
blender::int2 event_xy_offset
RegionView3D * rv3d
void init_navigation(bContext *C, const wmEvent *event, const ViewOpsType *nav_type, const float dyn_ofs_override[3]=nullptr, const bool use_cursor_init=false)
struct ViewOpsData::@005374042217004103135116130176222021322117027130 init
void init_context(bContext *C)
const char * idname
wmOperatorStatus(* apply_fn)(bContext *C, ViewOpsData *vod, const eV3D_OpEvent event_code, const int xy[2])
wmOperatorStatus(* init_fn)(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr)
bool(* poll_fn)(bContext *C)
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
void * customdata
Definition WM_types.hh:804
const char * name
Definition WM_types.hh:1030
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void view3d_boxview_sync(ScrArea *area, ARegion *region)
void view3d_navigate_cancel_fn(bContext *C, wmOperator *op)
static const ViewOpsType * view3d_navigation_type_from_idname(const char *idname)
wmOperatorStatus view3d_navigate_invoke_impl(bContext *C, wmOperator *op, const wmEvent *event, const ViewOpsType *nav_type)
void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag)
void viewops_data_free(bContext *C, ViewOpsData *vod)
ViewOpsData * viewops_data_create(bContext *C, const wmEvent *event, const ViewOpsType *nav_type, const bool use_cursor_init)
static void view3d_orbit_apply_dyn_ofs_ortho_correction(float ofs[3], const float viewquat_old[4], const float viewquat_new[4], const float dyn_ofs[3])
wmOperatorStatus view3d_navigate_modal_fn(bContext *C, wmOperator *op, const wmEvent *event)
void view3d_orbit_apply_dyn_ofs(float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], const float viewquat_new[4], const float dyn_ofs[3])
bool view3d_rotation_poll(bContext *C)
bool view3d_location_poll(bContext *C)
static eViewOpsFlag navigate_pivot_get(bContext *C, Depsgraph *depsgraph, ARegion *region, View3D *v3d, const wmEvent *event, eViewOpsFlag viewops_flag, const float dyn_ofs_override[3], float r_pivot[3])
static eViewOpsFlag viewops_flag_from_prefs()
static wmOperatorStatus view3d_navigation_invoke_generic(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr, const ViewOpsType *nav_type, const float dyn_ofs_override[3])
bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
void viewmove_apply(ViewOpsData *vod, int x, int y)
void ED_view3d_navigation_free(bContext *C, ViewOpsData *vod)
void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3])
static eV3D_OpEvent view3d_navigate_event(ViewOpsData *vod, const wmEvent *event)
void axis_set_view(bContext *C, View3D *v3d, ARegion *region, const float quat_[4], char view, char view_axis_roll, int perspo, const float *align_to_quat, const int smooth_viewtx)
static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
bool ED_view3d_navigation_do(bContext *C, ViewOpsData *vod, const wmEvent *event, const float depth_loc_override[3])
ViewOpsData * ED_view3d_navigation_init(bContext *C, const wmKeyMapItem *kmi_merge)
bool view3d_zoom_or_dolly_or_rotation_poll(bContext *C)
void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
bool view3d_zoom_or_dolly_poll(bContext *C)
const ViewOpsType ViewOpsType_zoom
void ED_view3d_smooth_view(bContext *C, View3D *v3d, ARegion *region, int smooth_viewtx, const V3D_SmoothParams *sview)
const ViewOpsType ViewOpsType_pan
eViewOpsFlag
@ VIEWOPS_FLAG_ORBIT_SELECT
@ VIEWOPS_FLAG_DEPTH_NAVIGATE
@ VIEWOPS_FLAG_INIT_ZFAC
@ VIEWOPS_FLAG_ZOOM_TO_MOUSE
@ VIEWOPS_FLAG_PERSP_ENSURE
const ViewOpsType ViewOpsType_rotate
eV3D_OpEvent
@ VIEW_CANCEL
@ VIEWROT_MODAL_SWITCH_ROTATE
@ VIEWROT_MODAL_AXIS_SNAP_ENABLE
@ VIEW_MODAL_CANCEL
@ VIEWROT_MODAL_SWITCH_MOVE
@ VIEW_MODAL_CONFIRM
@ VIEWROT_MODAL_SWITCH_ZOOM
@ VIEWROT_MODAL_AXIS_SNAP_DISABLE
void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3])
eV3D_OpPropFlag
@ V3D_OP_PROP_USE_MOUSE_INIT
@ V3D_OP_PROP_DELTA
@ V3D_OP_PROP_USE_ALL_REGIONS
@ V3D_OP_PROP_MOUSE_CO
const ViewOpsType ViewOpsType_move
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
#define V3D_OP_TRACKBALLSIZE
void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
Definition wm.cc:321
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
bool WM_event_match(const wmEvent *winevent, const wmKeyMapItem *kmi)
#define ISKEYMODIFIER(event_type)
@ TIMER
@ EVT_MODAL_MAP
@ EVT_RIGHTCTRLKEY
@ EVT_OSKEY
@ EVT_LEFTCTRLKEY
@ MOUSEMOVE
@ EVT_RIGHTALTKEY
@ EVT_LEFTALTKEY
@ EVT_ESCKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
@ EVT_HYPER
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
wmKeyMapItem * WM_keymap_add_item_copy(wmKeyMap *keymap, wmKeyMapItem *kmi_src)
Definition wm_keymap.cc:565
void WM_keymap_clear(wmKeyMap *keymap)
Definition wm_keymap.cc:446
wmKeyMap * WM_keymap_find_all(wmWindowManager *wm, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:907
void WM_keyconfig_update_suppress_begin()
void WM_keyconfig_update_suppress_end()
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
uint8_t flag
Definition wm_window.cc:139