Blender V5.0
view3d_navigate_zoom_border.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_camera_types.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_vector.h"
14#include "BLI_rect.h"
15
16#include "BKE_context.hh"
17#include "BKE_report.hh"
18
19#include "WM_api.hh"
20
21#include "RNA_access.hh"
22
23#include "view3d_intern.hh"
24#include "view3d_navigate.hh" /* own include */
25
26/* -------------------------------------------------------------------- */
29
31{
32 ARegion *region = CTX_wm_region(C);
33 View3D *v3d = CTX_wm_view3d(C);
35 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
36
37 /* Zooms in on a border drawn by the user */
38 rcti rect;
39 float dvec[3], vb[2], xscale, yscale;
40
41 /* SMOOTHVIEW */
42 float dist_new;
43 float ofs_new[3];
44
45 /* ZBuffer depth vars */
46 float depth_close = FLT_MAX;
47 float cent[2], p[3];
48
49 /* NOTE: otherwise opengl won't work. */
51
52 /* get box select values using rna */
54
55 /* check if zooming in/out view */
56 const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
57
59
61 region,
62 v3d,
63 nullptr,
65 true,
66 nullptr);
67 {
68 /* avoid allocating the whole depth buffer */
69 ViewDepths depth_temp = {0};
70
71 /* avoid view3d_update_depths() for speed. */
72 view3d_depths_rect_create(region, &rect, &depth_temp);
73
74 /* find the closest Z pixel */
75 depth_close = view3d_depth_near(&depth_temp);
76
77 MEM_SAFE_FREE(depth_temp.depths);
78 }
79
80 /* Resize border to the same ratio as the window. */
81 {
82 const float region_aspect = float(region->winx) / float(region->winy);
83 if ((float(BLI_rcti_size_x(&rect)) / float(BLI_rcti_size_y(&rect))) < region_aspect) {
84 BLI_rcti_resize_x(&rect, int(BLI_rcti_size_y(&rect) * region_aspect));
85 }
86 else {
87 BLI_rcti_resize_y(&rect, int(BLI_rcti_size_x(&rect) / region_aspect));
88 }
89 }
90
91 cent[0] = (float(rect.xmin) + float(rect.xmax)) / 2;
92 cent[1] = (float(rect.ymin) + float(rect.ymax)) / 2;
93
94 if (rv3d->is_persp) {
95 float p_corner[3];
96
97 /* no depths to use, we can't do anything! */
98 if (depth_close == FLT_MAX) {
99 BKE_report(op->reports, RPT_ERROR, "Depth too large");
100 return OPERATOR_CANCELLED;
101 }
102 /* convert border to 3d coordinates */
103 if (!ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p) ||
104 !ED_view3d_unproject_v3(region, rect.xmin, rect.ymin, depth_close, p_corner))
105 {
106 return OPERATOR_CANCELLED;
107 }
108
109 sub_v3_v3v3(dvec, p, p_corner);
110 negate_v3_v3(ofs_new, p);
111
112 dist_new = len_v3(dvec);
113
114 /* Account for the lens, without this a narrow lens zooms in too close. */
115 dist_new *= (v3d->lens / DEFAULT_SENSOR_WIDTH);
116 }
117 else { /* orthographic */
118 /* find the current window width and height */
119 vb[0] = region->winx;
120 vb[1] = region->winy;
121
122 dist_new = rv3d->dist;
123
124 /* convert the drawn rectangle into 3d space */
125 if (depth_close != FLT_MAX && ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p))
126 {
127 negate_v3_v3(ofs_new, p);
128 }
129 else {
130 float xy_delta[2];
131 float zfac;
132
133 /* We can't use the depth, fall back to the old way that doesn't set the center depth */
134 copy_v3_v3(ofs_new, rv3d->ofs);
135
136 {
137 float tvec[3];
138 negate_v3_v3(tvec, ofs_new);
139 zfac = ED_view3d_calc_zfac(rv3d, tvec);
140 }
141
142 xy_delta[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f;
143 xy_delta[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f;
144 ED_view3d_win_to_delta(region, xy_delta, zfac, dvec);
145 /* center the view to the center of the rectangle */
146 sub_v3_v3(ofs_new, dvec);
147 }
148
149 /* work out the ratios, so that everything selected fits when we zoom */
150 xscale = (BLI_rcti_size_x(&rect) / vb[0]);
151 yscale = (BLI_rcti_size_y(&rect) / vb[1]);
152 dist_new *= max_ff(xscale, yscale);
153 }
154
155 if (!zoom_in) {
156 sub_v3_v3v3(dvec, ofs_new, rv3d->ofs);
157 dist_new = rv3d->dist * (rv3d->dist / dist_new);
158 add_v3_v3v3(ofs_new, rv3d->ofs, dvec);
159 }
160
161 /* clamp after because we may have been zooming out */
162 CLAMP(dist_new, dist_range.min, dist_range.max);
163
164 const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
165 if (rv3d->persp == RV3D_CAMOB) {
167 if (is_camera_lock) {
169 }
170 else {
172 }
173 }
174 V3D_SmoothParams sview_params = {};
175 sview_params.ofs = ofs_new;
176 sview_params.dist = &dist_new;
177 sview_params.undo_str = op->type->name;
178
179 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview_params);
180
181 if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
183 }
184
185 return OPERATOR_FINISHED;
186}
187
189{
190 /* identifiers */
191 ot->name = "Zoom to Border";
192 ot->description = "Zoom in the view to the nearest object contained in the border";
193 ot->idname = "VIEW3D_OT_zoom_border";
194
195 /* API callbacks. */
196 ot->invoke = WM_gesture_box_invoke;
198 ot->modal = WM_gesture_box_modal;
199 ot->cancel = WM_gesture_box_cancel;
200
202
203 /* flags */
204 ot->flag = 0;
205
206 /* properties */
208}
209
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
MINLINE float max_ff(float a, float b)
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_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rcti_resize_y(struct rcti *rect, int y)
Definition rct.cc:615
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rcti_resize_x(struct rcti *rect, int x)
Definition rct.cc:609
#define CLAMP(a, b, c)
#define DEFAULT_SENSOR_WIDTH
#define RV3D_LOCK_FLAGS(rv3d)
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_BOXVIEW
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
void ED_view3d_depth_override(Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obact, eV3DDepthOverrideMode mode, bool use_overlay, ViewDepths **r_depths)
blender::Bounds< float > ED_view3d_dist_soft_range_get(const View3D *v3d, bool use_persp_range)
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, char persp)
bool ED_view3d_unproject_v3(const ARegion *region, float regionx, float regiony, float regionz, float world[3])
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 view3d_operator_needs_gpu(const bContext *C)
void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
BPy_StructRNA * depsgraph
nullptr float
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
#define FLT_MAX
Definition stdcycles.h:14
const char * undo_str
float * depths
Definition ED_view3d.hh:89
int ymin
int ymax
int xmin
int xmax
const char * name
Definition WM_types.hh:1033
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void view3d_depths_rect_create(ARegion *region, rcti *rect, ViewDepths *r_d)
float view3d_depth_near(ViewDepths *d)
void view3d_boxview_sync(ScrArea *area, ARegion *region)
bool view3d_zoom_or_dolly_poll(bContext *C)
void ED_view3d_smooth_view(bContext *C, View3D *v3d, ARegion *region, int smooth_viewtx, const V3D_SmoothParams *sview)
static wmOperatorStatus view3d_zoom_border_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_zoom_border(wmOperatorType *ot)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_rect)
void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
int WM_operator_smooth_viewtx_get(const wmOperator *op)