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