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
8
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/* -------------------------------------------------------------------- */
77
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
211 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, true, nullptr);
212 }
213
214 const bool is_set = ED_view3d_autodist(region, v3d, event->mval, r_pivot, fallback_depth_pt);
215
216 ED_view3d_autodist_last_set(win, event, r_pivot, is_set);
217 }
218
220}
221
223 const wmEvent *event,
224 const ViewOpsType *nav_type,
225 const float dyn_ofs_override[3],
226 const bool use_cursor_init)
227{
228 using namespace blender;
229 this->nav_type = nav_type;
231
232 if (!use_cursor_init) {
234 }
235
236 bool calc_rv3d_dist = true;
237#ifdef WITH_INPUT_NDOF
238 if (ELEM(nav_type,
239 &ViewOpsType_ndof_orbit,
240 &ViewOpsType_ndof_orbit_zoom,
241 &ViewOpsType_ndof_pan,
242 &ViewOpsType_ndof_all))
243 {
244 calc_rv3d_dist = false;
245
246 /* When using "Free" NDOF navigation, ignore "Orbit Around Selected" preference.
247 * Logically it doesn't make sense to use the selection as a pivot when the first-person
248 * navigation pivots from the view-point. This also interferes with zoom-speed,
249 * causing zoom-speed scale based on the distance to the selection center, see: #115253. */
250 if ((U.ndof_flag & NDOF_MODE_ORBIT) == 0) {
252 }
253 }
254#endif
255
256 /* Set the view from the camera, if view locking is enabled.
257 * we may want to make this optional but for now its needed always. */
259
260 this->state_backup();
261
262 if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
263 if (ED_view3d_persp_ensure(depsgraph, this->v3d, this->region)) {
264 /* If we're switching from camera view to the perspective one,
265 * need to tag viewport update, so camera view and borders are properly updated. */
267 }
268 }
269
271 float pivot_new[3];
272 eViewOpsFlag pivot_type = navigate_pivot_get(
273 C, depsgraph, region, v3d, event, viewops_flag, dyn_ofs_override, pivot_new);
274
276 viewops_flag |= pivot_type;
277
278 negate_v3_v3(this->dyn_ofs, pivot_new);
279 this->use_dyn_ofs = true;
280
281 if (pivot_type == VIEWOPS_FLAG_DEPTH_NAVIGATE) {
282 /* Ensure we'll always be able to zoom into the new pivot point and panning won't go bad when
283 * dist is zero. Therefore, set a new #RegionView3D::ofs and #RegionView3D::dist so that the
284 * dist value becomes the distance from the new pivot point. */
285
286 if (rv3d->is_persp) {
287 float my_origin[3]; /* Original #RegionView3D.ofs. */
288 float my_pivot[3]; /* View pivot. */
289 float dvec[3];
290
291 negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
292
293 /* remove dist value */
294 float3 upvec;
295 upvec[0] = upvec[1] = 0;
296 upvec[2] = rv3d->dist;
297 float3x3 mat = float3x3(float4x4(rv3d->viewinv));
298
299 upvec = math::transform_point(mat, upvec);
300 add_v3_v3v3(my_pivot, my_origin, upvec);
301
302 /* find a new ofs value that is along the view axis
303 * (rather than the mouse location) */
304 float lambda = closest_to_line_v3(dvec, pivot_new, my_pivot, my_origin);
305
306 negate_v3_v3(rv3d->ofs, dvec);
307 rv3d->dist = len_v3v3(my_pivot, dvec);
308
309 if (lambda < 0.0f) {
310 /* The distance is actually negative. */
311 rv3d->dist *= -1;
312 }
313 }
314 else {
315 const float mval_region_mid[2] = {float(region->winx) / 2.0f, float(region->winy) / 2.0f};
316 ED_view3d_win_to_3d(v3d, region, pivot_new, mval_region_mid, rv3d->ofs);
317 negate_v3(rv3d->ofs);
318 }
319 }
320
321 /* Reinitialize `this->init.dist` and `this->init.ofs` as these values may have changed
322 * when #ED_view3d_persp_ensure was called or when the operator uses `Auto Depth`.
323 *
324 * XXX: The initial state captured by #ViewOpsData::state_backup is being modified here.
325 * This causes the state not to be fully restored when canceling a navigation operation. */
326 this->init.dist = rv3d->dist;
327 copy_v3_v3(this->init.ofs, rv3d->ofs);
328 }
329
331 float tvec[3];
332 negate_v3_v3(tvec, rv3d->ofs);
333 this->init.zfac = ED_view3d_calc_zfac(rv3d, tvec);
334 }
335
336 this->init.persp_with_auto_persp_applied = rv3d->persp;
337
338 if (event) {
339 this->init.event_type = event->type;
340 copy_v2_v2_int(this->init.event_xy, event->xy);
341 copy_v2_v2_int(this->prev.event_xy, event->xy);
342
343 if (use_cursor_init) {
344 zero_v2_int(this->init.event_xy_offset);
345 }
346 else {
347 /* Simulate the event starting in the middle of the region. */
348 this->init.event_xy_offset[0] = BLI_rcti_cent_x(&this->region->winrct) - event->xy[0];
349 this->init.event_xy_offset[1] = BLI_rcti_cent_y(&this->region->winrct) - event->xy[1];
350 }
351
352 /* For dolly */
353 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
354 ED_view3d_win_to_vector(region, mval, this->init.mousevec);
355
356 {
357 int event_xy_offset[2];
358 add_v2_v2v2_int(event_xy_offset, event->xy, this->init.event_xy_offset);
359
360 /* For rotation with trackball rotation. */
361 calctrackballvec(&region->winrct, event_xy_offset, this->init.trackvec);
362 }
363 }
364
365 copy_qt_qt(this->curr.viewquat, rv3d->viewquat);
366
367 this->reverse = 1.0f;
368 if (rv3d->persmat[2][1] < 0.0f) {
369 this->reverse = -1.0f;
370 }
371
372 this->viewops_flag = viewops_flag;
373
374 /* Default. */
375 this->use_dyn_ofs_ortho_correction = false;
376
377 rv3d->rflag |= RV3D_NAVIGATING;
378}
379
381{
382 this->rv3d->rflag &= ~RV3D_NAVIGATING;
383
384 if (this->timer) {
385 WM_event_timer_remove(CTX_wm_manager(C), this->timer->win, this->timer);
386 }
387
388 MEM_SAFE_FREE(this->init.dial);
389
390 /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw
391 * faster while navigation operator runs. */
393}
394
396
397/* -------------------------------------------------------------------- */
400
401/* Used for navigation utility in operators. */
403 /* To track only the navigation #wmKeyMapItem items and allow changes to them, an internal
404 * #wmKeyMap is created with their copy. */
406
407 /* Used by #ED_view3d_navigation_do. */
409
410 ViewOpsData_Utility(bContext *C, const wmKeyMapItem *kmi_merge = nullptr)
412 {
413 this->init_context(C);
414
417
419
420 wmKeyMap keymap_tmp = {};
421
422 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
423 if (!STRPREFIX(kmi->idname, "VIEW3D")) {
424 continue;
425 }
426 if (kmi->flag & KMI_INACTIVE) {
427 continue;
428 }
429 if (view3d_navigation_type_from_idname(kmi->idname) == nullptr) {
430 continue;
431 }
432
433 wmKeyMapItem *kmi_cpy = WM_keymap_add_item_copy(&keymap_tmp, kmi);
434 if (kmi_merge) {
435 if (kmi_merge->shift == 1 || ELEM(kmi_merge->type, EVT_RIGHTSHIFTKEY, EVT_LEFTSHIFTKEY)) {
436 kmi_cpy->shift = 1;
437 }
438 if (kmi_merge->ctrl == 1 || ELEM(kmi_merge->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
439 kmi_cpy->ctrl = 1;
440 }
441 if (kmi_merge->alt == 1 || ELEM(kmi_merge->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
442 kmi_cpy->alt = 1;
443 }
444 if (kmi_merge->oskey == 1 || ELEM(kmi_merge->type, EVT_OSKEY)) {
445 kmi_cpy->oskey = 1;
446 }
447 if (!ISKEYMODIFIER(kmi_merge->type)) {
448 kmi_cpy->keymodifier = kmi_merge->type;
449 }
450 }
451 }
452
453 /* Weak, but only the keymap items from the #wmKeyMap struct are needed here. */
454 this->keymap_items = keymap_tmp.items;
455
457 }
458
460 {
461 /* Weak, but rebuild the struct #wmKeyMap to clear the keymap items. */
463
464 wmKeyMap keymap_tmp = {};
465 keymap_tmp.items = this->keymap_items;
466 WM_keymap_clear(&keymap_tmp);
467
469 }
470
471#ifdef WITH_CXX_GUARDEDALLOC
472 MEM_CXX_CLASS_ALLOC_FUNCS("ViewOpsData_Utility")
473#endif
474};
475
476static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
477{
479 return false;
480 }
481
482 const RegionView3D *rv3d = CTX_wm_region_view3d(C);
483 return !(RV3D_LOCK_FLAGS(rv3d) & viewlock);
484}
485
487{
488 if (event->type == EVT_MODAL_MAP) {
489 switch (event->val) {
491 return VIEW_CANCEL;
493 return VIEW_CONFIRM;
495 vod->axis_snap = true;
496 return VIEW_APPLY;
499 vod->axis_snap = false;
500 return VIEW_APPLY;
504 const ViewOpsType *nav_type_new = (event->val == VIEWROT_MODAL_SWITCH_ZOOM) ?
506 (event->val == VIEWROT_MODAL_SWITCH_MOVE) ?
509 if (nav_type_new == vod->nav_type) {
510 break;
511 }
512 vod->nav_type = nav_type_new;
513 return VIEW_APPLY;
514 }
515 }
516 }
517 else {
518 if (event->type == TIMER && event->customdata == vod->timer) {
519 /* Zoom uses timer for continuous zoom. */
520 return VIEW_APPLY;
521 }
522 if (event->type == MOUSEMOVE) {
523 return VIEW_APPLY;
524 }
525 if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
526 return VIEW_CONFIRM;
527 }
528 if (event->type == EVT_ESCKEY && event->val == KM_PRESS) {
529 return VIEW_CANCEL;
530 }
531 }
532
533 return VIEW_PASS;
534}
535
537 ViewOpsData *vod,
538 const wmEvent *event,
540 const ViewOpsType *nav_type,
541 const float dyn_ofs_override[3])
542{
543 if (!nav_type->init_fn) {
544 return OPERATOR_CANCELLED;
545 }
546
547 bool use_cursor_init = false;
548 if (PropertyRNA *prop = RNA_struct_find_property(ptr, "use_cursor_init")) {
549 use_cursor_init = RNA_property_boolean_get(ptr, prop);
550 }
551
552 vod->init_navigation(C, event, nav_type, dyn_ofs_override, use_cursor_init);
554
555 return nav_type->init_fn(C, vod, event, ptr);
556}
557
559 wmOperator *op,
560 const wmEvent *event,
561 const ViewOpsType *nav_type)
562{
563 ViewOpsData *vod = new ViewOpsData();
564 vod->init_context(C);
565 int ret = view3d_navigation_invoke_generic(C, vod, event, op->ptr, nav_type, nullptr);
566 op->customdata = (void *)vod;
567
571 }
572
573 viewops_data_free(C, vod);
574 op->customdata = nullptr;
575 return ret;
576}
577
579
580/* -------------------------------------------------------------------- */
583
588
593
598
600{
601 ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
602
603 const ViewOpsType *nav_type_prev = vod->nav_type;
604 const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
605 if (nav_type_prev != vod->nav_type) {
606 wmOperatorType *ot_new = WM_operatortype_find(vod->nav_type->idname, false);
607 WM_operator_type_set(op, ot_new);
608 vod->end_navigation(C);
609 return view3d_navigation_invoke_generic(C, vod, event, op->ptr, vod->nav_type, nullptr);
610 }
611
612 int ret = vod->nav_type->apply_fn(C, vod, event_code, event->xy);
613
614 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
615 if (ret & OPERATOR_FINISHED) {
617 }
618 viewops_data_free(C, vod);
619 op->customdata = nullptr;
620 }
621
622 return ret;
623}
624
626{
627 viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
628 op->customdata = nullptr;
629}
630
632
633/* -------------------------------------------------------------------- */
636
638{
640 PropertyRNA *prop;
641 prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX);
643 prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX);
645 }
646 if (flag & V3D_OP_PROP_DELTA) {
647 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
648 }
650 PropertyRNA *prop;
651 prop = RNA_def_boolean(
652 ot->srna, "use_all_regions", false, "All Regions", "View selected for all regions");
654 }
657 }
658}
659
661
662/* -------------------------------------------------------------------- */
665
666void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3])
667{
668 const float radius = V3D_OP_TRACKBALLSIZE;
669 const float t = radius / float(M_SQRT2);
670 const float size[2] = {float(BLI_rcti_size_x(rect)), float(BLI_rcti_size_y(rect))};
671 /* Aspect correct so dragging in a non-square view doesn't squash the direction.
672 * So diagonal motion rotates the same direction the cursor is moving. */
673 const float size_min = min_ff(size[0], size[1]);
674 const float aspect[2] = {size_min / size[0], size_min / size[1]};
675
676 /* Normalize x and y. */
677 r_dir[0] = (event_xy[0] - BLI_rcti_cent_x(rect)) / ((size[0] * aspect[0]) / 2.0);
678 r_dir[1] = (event_xy[1] - BLI_rcti_cent_y(rect)) / ((size[1] * aspect[1]) / 2.0);
679 const float d = len_v2(r_dir);
680 if (d < t) {
681 /* Inside sphere. */
682 r_dir[2] = sqrtf(square_f(radius) - square_f(d));
683 }
684 else {
685 /* On hyperbola. */
686 r_dir[2] = square_f(t) / d;
687 }
688}
689
690void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
691 const float ofs_old[3],
692 const float viewquat_old[4],
693 const float viewquat_new[4],
694 const float dyn_ofs[3])
695{
696 float q[4];
697 invert_qt_qt_normalized(q, viewquat_old);
698 mul_qt_qtqt(q, q, viewquat_new);
699
701
702 sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs);
703 mul_qt_v3(q, r_ofs);
704 add_v3_v3(r_ofs, dyn_ofs);
705}
706
708 const float viewquat_old[4],
709 const float viewquat_new[4],
710 const float dyn_ofs[3])
711{
712 /* NOTE(@ideasman42): While orbiting in orthographic mode the "depth" of the offset
713 * (position along the views Z-axis) is only noticeable when the view contents is clipped.
714 * The likelihood of clipping depends on the clipping range & size of the scene.
715 * In practice some users might not run into this, however using dynamic-offset in
716 * orthographic views can cause the depth of the offset to drift while navigating the view,
717 * causing unexpected clipping that seems like a bug from the user perspective, see: #104385.
718 *
719 * Imagine a camera is focused on a distant object. Now imagine a closer object in front of
720 * the camera is used as a pivot, the camera is rotated to view it from the side (~90d rotation).
721 * The outcome is the camera is now focused on a distant region to the left/right.
722 * The new focal point is unlikely to point to anything useful (unless by accident).
723 * Instead of a focal point - the `rv3d->ofs` is being manipulated in this case.
724 *
725 * Resolve by moving #RegionView3D::ofs so it is depth-aligned to `dyn_ofs`,
726 * this is interpolated by the amount of rotation so minor rotations don't cause
727 * the view-clipping to suddenly jump.
728 *
729 * Perspective Views
730 * =================
731 *
732 * This logic could also be applied to perspective views because the issue of the `ofs`
733 * being a location which isn't useful exists there too, however the problem where this location
734 * impacts the clipping does *not* exist, as the clipping range starts from the view-point
735 * (`ofs` + `dist` along the view Z-axis) unlike orthographic views which center around `ofs`.
736 * Nevertheless there will be cases when having `ofs` and a large `dist` pointing nowhere doesn't
737 * give ideal behavior (zooming may jump in larger than expected steps and panning the view may
738 * move too much in relation to nearby objects - for e.g.). So it's worth investigating but
739 * should be done with extra care as changing `ofs` in perspective view also requires changing
740 * the `dist` which could cause unexpected results if the calculated `dist` happens to be small.
741 * So disable this workaround in perspective view unless there are clear benefits to enabling. */
742
743 float q_inv[4];
744
745 float view_z_init[3] = {0.0f, 0.0f, 1.0f};
746 invert_qt_qt_normalized(q_inv, viewquat_old);
747 mul_qt_v3(q_inv, view_z_init);
748
749 float view_z_curr[3] = {0.0f, 0.0f, 1.0f};
750 invert_qt_qt_normalized(q_inv, viewquat_new);
751 mul_qt_v3(q_inv, view_z_curr);
752
753 const float angle_cos = max_ff(0.0f, dot_v3v3(view_z_init, view_z_curr));
754 /* 1.0 or more means no rotation, there is nothing to do in that case. */
755 if (LIKELY(angle_cos < 1.0f)) {
756 const float dot_ofs_curr = dot_v3v3(view_z_curr, ofs);
757 const float dot_ofs_next = dot_v3v3(view_z_curr, dyn_ofs);
758 const float ofs_delta = dot_ofs_next - dot_ofs_curr;
759 if (LIKELY(ofs_delta != 0.0f)) {
760 /* Calculate a factor where 0.0 represents no rotation and 1.0 represents 90d or more.
761 * NOTE: Without applying the factor, the distances immediately changes
762 * (useful for testing), but not good for the users experience as minor rotations
763 * should not immediately adjust the depth. */
764 const float factor = acosf(angle_cos) / M_PI_2;
765 madd_v3_v3fl(ofs, view_z_curr, ofs_delta * factor);
766 }
767 }
768}
769
770void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
771{
772 if (vod->use_dyn_ofs) {
773 RegionView3D *rv3d = vod->rv3d;
775 rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
776
779 rv3d->ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
780 }
781 }
782}
783
784bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
785{
786 using namespace blender;
787 static float3 lastofs = float3(0);
788 bool is_set = false;
789
791 Scene *scene = CTX_data_scene(C);
794 View3D *v3d = CTX_wm_view3d(C);
795 BKE_view_layer_synced_ensure(scene_eval, view_layer_eval);
796 Object *ob_act_eval = BKE_view_layer_active_object_get(view_layer_eval);
797 Object *ob_act = DEG_get_original_object(ob_act_eval);
798
799 if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
800 /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
801 ((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0)
802 {
803 BKE_paint_stroke_get_average(scene, ob_act_eval, lastofs);
804 is_set = true;
805 }
806 else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
807 Curve *cu = static_cast<Curve *>(ob_act_eval->data);
808 EditFont *ef = cu->editfont;
809
810 lastofs = float3(0);
811 for (int i = 0; i < 4; i++) {
812 lastofs += ef->textcurs[i];
813 }
814 lastofs *= 0.25f;
815
816 lastofs = math::transform_point(ob_act_eval->object_to_world(), lastofs);
817
818 is_set = true;
819 }
820 else if (ob_act == nullptr || ob_act->mode == OB_MODE_OBJECT) {
821 /* Object mode uses bounding-box centers. */
822 int total = 0;
823 float3 select_center(0);
824
825 zero_v3(select_center);
826 LISTBASE_FOREACH (const Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
827 if (BASE_SELECTED(v3d, base_eval)) {
828 /* Use the bounding-box if we can. */
829 const Object *ob_eval = base_eval->object;
830
831 if (const std::optional<Bounds<float3>> bounds = BKE_object_boundbox_get(ob_eval)) {
832 const float3 center = math::midpoint(bounds->min, bounds->max);
833 select_center += math::transform_point(ob_eval->object_to_world(), center);
834 }
835 else {
836 add_v3_v3(select_center, ob_eval->object_to_world().location());
837 }
838 total++;
839 }
840 }
841 if (total) {
842 mul_v3_fl(select_center, 1.0f / float(total));
843 copy_v3_v3(lastofs, select_center);
844 is_set = true;
845 }
846 }
847 else {
848 /* If there's no selection, `lastofs` is unmodified and last value since static. */
850 }
851
852 copy_v3_v3(r_dyn_ofs, lastofs);
853
854 return is_set;
855}
856
858 const wmEvent *event,
859 const ViewOpsType *nav_type,
860 const bool use_cursor_init)
861{
862 ViewOpsData *vod = new ViewOpsData();
863 vod->init_context(C);
864 vod->init_navigation(C, event, nav_type, nullptr, use_cursor_init);
865 return vod;
866}
867
869{
870 if (!vod) {
871 return;
872 }
873 vod->end_navigation(C);
874 delete vod;
875}
876
878
879/* -------------------------------------------------------------------- */
882
887 View3D *v3d,
888 ARegion *region,
889 const float quat_[4],
890 char view,
891 char view_axis_roll,
892 int perspo,
893 const float *align_to_quat,
894 const int smooth_viewtx)
895{
896 /* no nullptr check is needed, poll checks */
897 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
898
899 float quat[4];
900 const short orig_persp = rv3d->persp;
901 const char orig_view = rv3d->view;
902 const char orig_view_axis_roll = rv3d->view_axis_roll;
903
904 normalize_qt_qt(quat, quat_);
905
906 if (align_to_quat) {
907 mul_qt_qtqt(quat, quat, align_to_quat);
908 rv3d->view = view = RV3D_VIEW_USER;
910 }
911 else {
912 rv3d->view = view;
913 rv3d->view_axis_roll = view_axis_roll;
914 }
915
916 /* Redrawing when changes are detected is needed because the current view
917 * orientation may be a "User" view that matches the axis exactly.
918 * In this case smooth-view exits early as no view transition is needed.
919 * However, changing the view must redraw the region as it changes the
920 * viewport name & grid drawing. */
921 if ((rv3d->view != orig_view) || (rv3d->view_axis_roll != orig_view_axis_roll)) {
922 ED_region_tag_redraw(region);
923 }
924
926 return;
927 }
928
929 if (U.uiflag & USER_AUTOPERSP) {
930 rv3d->persp = RV3D_VIEW_IS_AXIS(view) ? RV3D_ORTHO : perspo;
931 }
932 else if (rv3d->persp == RV3D_CAMOB) {
933 rv3d->persp = perspo;
934 }
935 if (rv3d->persp != orig_persp) {
936 ED_region_tag_redraw(region);
937 }
938
939 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
940 /* to camera */
941 V3D_SmoothParams sview = {nullptr};
942 sview.camera_old = v3d->camera;
943 sview.ofs = rv3d->ofs;
944 sview.quat = quat;
945 /* No undo because this switches to/from camera. */
946 sview.undo_str = nullptr;
947
948 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
949 }
950 else if (orig_persp == RV3D_CAMOB && v3d->camera) {
951 /* from camera */
952 float ofs[3], dist;
953
954 copy_v3_v3(ofs, rv3d->ofs);
955 dist = rv3d->dist;
956
957 /* so we animate _from_ the camera location */
959 v3d->camera);
960 ED_view3d_from_object(camera_eval, rv3d->ofs, nullptr, &rv3d->dist, nullptr);
961
962 V3D_SmoothParams sview = {nullptr};
963 sview.camera_old = camera_eval;
964 sview.ofs = ofs;
965 sview.quat = quat;
966 sview.dist = &dist;
967 /* No undo because this switches to/from camera. */
968 sview.undo_str = nullptr;
969
970 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
971 }
972 else {
973 /* rotate around selection */
974 const float *dyn_ofs_pt = nullptr;
975 float dyn_ofs[3];
976
977 if (U.uiflag & USER_ORBIT_SELECTION) {
978 if (view3d_orbit_calc_center(C, dyn_ofs)) {
979 negate_v3(dyn_ofs);
980 dyn_ofs_pt = dyn_ofs;
981 }
982 }
983
984 /* no camera involved */
985 V3D_SmoothParams sview = {nullptr};
986 sview.quat = quat;
987 sview.dyn_ofs = dyn_ofs_pt;
988 /* No undo because this switches to/from camera. */
989 sview.undo_str = nullptr;
990
991 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
992 }
993}
994
995void viewmove_apply(ViewOpsData *vod, int x, int y)
996{
997 const float event_ofs[2] = {
998 float(vod->prev.event_xy[0] - x),
999 float(vod->prev.event_xy[1] - y),
1000 };
1001
1002 if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
1003 ED_view3d_camera_view_pan(vod->region, event_ofs);
1004 }
1005 else if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) {
1006 vod->rv3d->ofs_lock[0] -= (event_ofs[0] * 2.0f) / float(vod->region->winx);
1007 vod->rv3d->ofs_lock[1] -= (event_ofs[1] * 2.0f) / float(vod->region->winy);
1008 }
1009 else {
1010 float dvec[3];
1011
1012 ED_view3d_win_to_delta(vod->region, event_ofs, vod->init.zfac, dvec);
1013
1014 sub_v3_v3(vod->rv3d->ofs, dvec);
1015
1016 if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
1017 view3d_boxview_sync(vod->area, vod->region);
1018 }
1019 }
1020
1021 vod->prev.event_xy[0] = x;
1022 vod->prev.event_xy[1] = y;
1023
1024 ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
1025
1027}
1028
1030
1031/* -------------------------------------------------------------------- */
1034
1035/* Detect the navigation operation, by the name of the navigation operator (obtained by
1036 * `wmKeyMapItem::idname`) */
1037static const ViewOpsType *view3d_navigation_type_from_idname(const char *idname)
1038{
1039 const blender::Array<const ViewOpsType *> nav_types = {
1044// &ViewOpsType_orbit,
1045// &ViewOpsType_roll,
1046// &ViewOpsType_dolly,
1047#ifdef WITH_INPUT_NDOF
1048 &ViewOpsType_ndof_orbit,
1049 &ViewOpsType_ndof_orbit_zoom,
1050 &ViewOpsType_ndof_pan,
1051 &ViewOpsType_ndof_all,
1052#endif
1053 };
1054
1055 const char *op_name = idname + sizeof("VIEW3D_OT_");
1056 for (const ViewOpsType *nav_type : nav_types) {
1057 if (STREQ(op_name, nav_type->idname + sizeof("VIEW3D_OT_"))) {
1058 return nav_type;
1059 }
1060 }
1061 return nullptr;
1062}
1063
1065{
1066 /* Unlike `viewops_data_create`, `ED_view3d_navigation_init` creates a navigation context along
1067 * with an array of `wmKeyMapItem`s used for navigation. */
1068 if (!CTX_wm_region_view3d(C)) {
1069 return nullptr;
1070 }
1071
1072 return new ViewOpsData_Utility(C, kmi_merge);
1073}
1074
1076 ViewOpsData *vod,
1077 const wmEvent *event,
1078 const float depth_loc_override[3])
1079{
1080 if (!vod) {
1081 return false;
1082 }
1083
1084 wmEvent event_tmp;
1085 if (event->type == EVT_MODAL_MAP) {
1086 /* Workaround to use the original event values. */
1087 event_tmp = *event;
1088 event_tmp.type = event->prev_type;
1089 event_tmp.val = event->prev_val;
1090 event = &event_tmp;
1091 }
1092
1093 int op_return = OPERATOR_CANCELLED;
1094
1095 ViewOpsData_Utility *vod_intern = static_cast<ViewOpsData_Utility *>(vod);
1096 if (vod_intern->is_modal_event) {
1097 const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
1098 op_return = vod->nav_type->apply_fn(C, vod, event_code, event->xy);
1099 if (op_return != OPERATOR_RUNNING_MODAL) {
1100 vod->end_navigation(C);
1101 vod_intern->is_modal_event = false;
1102 }
1103 }
1104 else {
1105 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &vod_intern->keymap_items) {
1106 if (!WM_event_match(event, kmi)) {
1107 continue;
1108 }
1109
1110 const ViewOpsType *nav_type = view3d_navigation_type_from_idname(kmi->idname);
1111 if (nav_type->poll_fn && !nav_type->poll_fn(C)) {
1112 break;
1113 }
1114
1116 C, vod, event, kmi->ptr, nav_type, depth_loc_override);
1117
1118 if (op_return == OPERATOR_RUNNING_MODAL) {
1119 vod_intern->is_modal_event = true;
1120 }
1121 else {
1122 vod->end_navigation(C);
1123 /* Postpone the navigation confirmation to the next call.
1124 * This avoids constant updating of the transform operation for example. */
1125 vod->rv3d->rflag |= RV3D_NAVIGATING;
1126 }
1127 break;
1128 }
1129 }
1130
1131 if (op_return != OPERATOR_CANCELLED) {
1132 /* Although #ED_view3d_update_viewmat is already called when redrawing the 3D View, do it here
1133 * as well, so the updated matrix values can be accessed by the operator. */
1135 vod->depsgraph, vod->scene, vod->v3d, vod->region, nullptr, nullptr, nullptr, false);
1136
1137 return true;
1138 }
1139 if (vod->rv3d->rflag & RV3D_NAVIGATING) {
1140 /* Add a fake confirmation. */
1141 vod->rv3d->rflag &= ~RV3D_NAVIGATING;
1142 return true;
1143 }
1144
1145 return false;
1146}
1147
1149{
1150 ViewOpsData_Utility *vod_intern = static_cast<ViewOpsData_Utility *>(vod);
1151 vod_intern->end_navigation(C);
1152 delete vod_intern;
1153}
1154
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)
@ RV3D_VIEW_AXIS_ROLL_0
#define RV3D_LOCK_FLAGS(rv3d)
@ RV3D_NAVIGATING
@ RV3D_VIEW_USER
@ RV3D_CAMOB
@ RV3D_ORTHO
@ RV3D_LOCK_ROTATION
@ RV3D_LOCK_LOCATION
@ RV3D_LOCK_ZOOM_AND_DOLLY
@ RV3D_BOXVIEW
@ V3D_AROUND_CENTER_MEDIAN
@ 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_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: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
#define C
Definition RandGen.cpp:29
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#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
VecBase< float, 3 > float3
#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)
MatBase< float, 4, 4 > float4x4
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:40
const char * undo_str
const float * dyn_ofs
struct Object * camera
ViewOpsData_Utility(bContext *C, const wmKeyMapItem *kmi_merge=nullptr)
const ViewOpsType * nav_type
char persp_with_auto_persp_applied
struct ViewOpsData::@273057311224271107250107334324315051373277242011 init
void end_navigation(bContext *C)
struct ViewOpsData::@130311065274055254065304001374237026063376370333 curr
eViewOpsFlag viewops_flag
bool use_dyn_ofs_ortho_correction
Depsgraph * depsgraph
ARegion * region
RegionView3D * rv3d
struct ViewOpsData::@273221176327302156026171144247373355370335020164 prev
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)
const char * idname
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
struct wmOperatorType * type
struct PointerRNA * ptr
MatBase< float, 3, 3 > float3x3
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
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)
@ 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
#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)
@ TIMER
@ EVT_MODAL_MAP
@ EVT_RIGHTCTRLKEY
@ EVT_OSKEY
@ EVT_LEFTCTRLKEY
@ MOUSEMOVE
@ EVT_RIGHTALTKEY
@ EVT_LEFTALTKEY
@ EVT_ESCKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
#define ISKEYMODIFIER(event_type)
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