Blender V4.3
view3d_navigate_view_all.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
10
11#include "BKE_armature.hh"
12#include "BKE_context.hh"
14#include "BKE_layer.hh"
15#include "BKE_object.hh"
16#include "BKE_paint.hh"
17#include "BKE_scene.hh"
18
19#include "BLI_bounds_types.hh"
20#include "BLI_math_matrix.h"
21#include "BLI_math_vector.h"
22
24
25#include "ED_mesh.hh"
26#include "ED_particle.hh"
27#include "ED_screen.hh"
28
29#include "WM_api.hh"
30#include "WM_message.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "view3d_intern.hh"
36#include "view3d_navigate.hh" /* own include */
37/* -------------------------------------------------------------------- */
43static bool view3d_object_skip_minmax(const View3D *v3d,
44 const RegionView3D *rv3d,
45 const Object *ob,
46 const bool skip_camera,
47 bool *r_only_center)
48{
49 BLI_assert(ob->id.orig_id == nullptr);
50 *r_only_center = false;
51
52 if (skip_camera && (ob == v3d->camera)) {
53 return true;
54 }
55
56 if ((ob->type == OB_EMPTY) && (ob->empty_drawtype == OB_EMPTY_IMAGE) &&
58 {
59 *r_only_center = true;
60 return false;
61 }
62
63 return false;
64}
65
66static void view3d_object_calc_minmax(Depsgraph *depsgraph,
67 Scene *scene,
68 Object *ob_eval,
69 const bool only_center,
70 float min[3],
71 float max[3])
72{
73 /* Account for duplis. */
74 if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) {
75 /* Use if duplis aren't found. */
76 if (only_center) {
77 minmax_v3v3_v3(min, max, ob_eval->object_to_world().location());
78 }
79 else {
80 BKE_object_minmax(ob_eval, min, max);
81 }
82 }
83}
84
86 View3D *v3d,
87 ARegion *region,
88 const float min[3],
89 const float max[3],
90 bool ok_dist,
91 const int smooth_viewtx)
92{
93 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
94 float afm[3];
95 float size;
96
98
99 /* SMOOTHVIEW */
100 float new_ofs[3];
101 float new_dist;
102
103 sub_v3_v3v3(afm, max, min);
104 size = max_fff(afm[0], afm[1], afm[2]);
105
106 if (ok_dist) {
107 char persp;
108
109 if (rv3d->is_persp) {
110 if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) {
111 persp = RV3D_CAMOB;
112 }
113 else {
114 persp = RV3D_PERSP;
115 }
116 }
117 else { /* ortho */
118 if (size < 0.0001f) {
119 /* bounding box was a single point so do not zoom */
120 ok_dist = false;
121 }
122 else {
123 /* adjust zoom so it looks nicer */
124 persp = RV3D_ORTHO;
125 }
126 }
127
128 if (ok_dist) {
130 new_dist = ED_view3d_radius_to_dist(
131 v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN);
132 if (rv3d->is_persp) {
133 /* don't zoom closer than the near clipping plane */
134 new_dist = max_ff(new_dist, v3d->clip_start * 1.5f);
135 }
136 }
137 }
138
139 mid_v3_v3v3(new_ofs, min, max);
140 negate_v3(new_ofs);
141
142 V3D_SmoothParams sview = {nullptr};
143 sview.ofs = new_ofs;
144 sview.dist = ok_dist ? &new_dist : nullptr;
145 /* The caller needs to use undo begin/end calls. */
146 sview.undo_str = nullptr;
147
148 if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
149 rv3d->persp = RV3D_PERSP;
150 sview.camera_old = v3d->camera;
151 }
152
153 ED_view3d_smooth_view(C, v3d, region, smooth_viewtx, &sview);
154
155 /* Smooth-view does view-lock #RV3D_BOXVIEW copy. */
156}
157
162 View3D *v3d,
163 const float min[3],
164 const float max[3],
165 const bool ok_dist,
166 const int smooth_viewtx)
167{
168 ScrArea *area = CTX_wm_area(C);
169 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
170 if (region->regiontype == RGN_TYPE_WINDOW) {
171 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
172 /* when using all regions, don't jump out of camera view,
173 * but _do_ allow locked cameras to be moved */
174 if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
175 view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
176 }
177 }
178 }
179}
180
183/* -------------------------------------------------------------------- */
190{
191 ScrArea *area = CTX_wm_area(C);
192 ARegion *region = CTX_wm_region(C);
193 View3D *v3d = CTX_wm_view3d(C);
195 Scene *scene = CTX_data_scene(C);
199
200 const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
201 const bool skip_camera = (ED_view3d_camera_lock_check(v3d, rv3d) ||
202 /* any one of the regions may be locked */
203 (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
204 const bool center = RNA_boolean_get(op->ptr, "center");
205 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
206
207 float min[3], max[3];
208 bool changed = false;
209
210 if (center) {
211 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
212 View3DCursor *cursor = &scene->cursor;
213 zero_v3(min);
214 zero_v3(max);
215 cursor->set_matrix(blender::float4x4::identity(), false);
216 }
217 else {
218 INIT_MINMAX(min, max);
219 }
220
221 BKE_view_layer_synced_ensure(scene_eval, view_layer_eval);
222 LISTBASE_FOREACH (Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
223 if (BASE_VISIBLE(v3d, base_eval)) {
224 bool only_center = false;
225 Object *ob = DEG_get_original_object(base_eval->object);
226 if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) {
227 continue;
228 }
229 view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max);
230 changed = true;
231 }
232 }
233
234 if (center) {
235 wmMsgBus *mbus = CTX_wm_message_bus(C);
236 WM_msg_publish_rna_prop(mbus, &scene->id, &scene->cursor, View3DCursor, location);
237
239 }
240
241 if (!changed) {
242 ED_region_tag_redraw(region);
243 /* TODO: should this be cancel?
244 * I think no, because we always move the cursor, with or without
245 * object, but in this case there is no change in the scene,
246 * only the cursor so I choice a ED_region_tag like
247 * view3d_smooth_view do for the center_cursor.
248 * See bug #22640.
249 */
250 return OPERATOR_FINISHED;
251 }
252
253 if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
254 /* This is an approximation, see function documentation for details. */
256 }
258
259 if (use_all_regions) {
260 view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx);
261 }
262 else {
263 view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx);
264 }
265
266 ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
267
268 return OPERATOR_FINISHED;
269}
270
272{
273 /* identifiers */
274 ot->name = "Frame All";
275 ot->description = "View all objects in scene";
276 ot->idname = "VIEW3D_OT_view_all";
277
278 /* api callbacks */
281
282 /* flags */
283 ot->flag = 0;
284
285 /* properties */
287 RNA_def_boolean(ot->srna, "center", false, "Center", "");
288}
289
292/* -------------------------------------------------------------------- */
299{
300 using namespace blender;
301 ScrArea *area = CTX_wm_area(C);
302 ARegion *region = CTX_wm_region(C);
303 View3D *v3d = CTX_wm_view3d(C);
305 Scene *scene = CTX_data_scene(C);
307 const Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
309 BKE_view_layer_synced_ensure(scene_eval, view_layer_eval);
310 Object *ob_eval = BKE_view_layer_active_object_get(view_layer_eval);
311 Object *obedit = CTX_data_edit_object(C);
312 const bool is_face_map = (region->gizmo_map && WM_gizmomap_is_any_selected(region->gizmo_map));
313 float3 min, max;
314 bool ok = false, ok_dist = true;
315 const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
316 const bool skip_camera = (ED_view3d_camera_lock_check(v3d, rv3d) ||
317 /* any one of the regions may be locked */
318 (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
319 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
320
321 INIT_MINMAX(min, max);
322 if (is_face_map) {
323 ob_eval = nullptr;
324 }
325
326 if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) {
327 /* hard-coded exception, we look for the one selected armature */
328 /* this is weak code this way, we should make a generic
329 * active/selection callback interface once... */
330 Base *base_eval;
331 for (base_eval = (Base *)BKE_view_layer_object_bases_get(view_layer_eval)->first; base_eval;
332 base_eval = base_eval->next)
333 {
334 if (BASE_SELECTED_EDITABLE(v3d, base_eval)) {
335 if (base_eval->object->type == OB_ARMATURE) {
336 if (base_eval->object->mode & OB_MODE_POSE) {
337 break;
338 }
339 }
340 }
341 }
342 if (base_eval) {
343 ob_eval = base_eval->object;
344 }
345 }
346
347 if (is_face_map) {
348 ok = WM_gizmomap_minmax(region->gizmo_map, true, true, min, max);
349 }
350 else if (obedit) {
351 /* only selected */
353 scene_eval, view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter)
354 {
355 ok |= ED_view3d_minmax_verts(scene_eval, ob_eval_iter, min, max);
356 }
358 }
359 else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) {
361 scene_eval, view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter)
362 {
363 const std::optional<Bounds<float3>> bounds = BKE_pose_minmax(ob_eval_iter, true);
364 if (bounds) {
365 minmax_v3v3_v3(min, max, bounds->min);
366 minmax_v3v3_v3(min, max, bounds->max);
367 ok = true;
368 }
369 }
371 }
372 else if (BKE_paint_select_face_test(ob_eval)) {
373 ok = paintface_minmax(ob_eval, min, max);
374 }
375 else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
376 ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
377 }
378 else if (ob_eval && (ob_eval->mode & OB_MODE_SCULPT_CURVES)) {
380 scene_eval, view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter)
381 {
382 ok |= ED_view3d_minmax_verts(scene_eval, ob_eval_iter, min, max);
383 }
385 }
386 else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
388 {
389 BKE_paint_stroke_get_average(scene, ob_eval, min);
390 copy_v3_v3(max, min);
391 ok = true;
392 ok_dist = false; /* don't zoom */
393 }
394 else {
395 LISTBASE_FOREACH (Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
396 if (BASE_SELECTED(v3d, base_eval)) {
397 bool only_center = false;
398 Object *ob = DEG_get_original_object(base_eval->object);
399 if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) {
400 continue;
401 }
402 view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max);
403 ok = true;
404 }
405 }
406 }
407
408 if (ok == 0) {
409 return OPERATOR_FINISHED;
410 }
411
412 if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
413 /* This is an approximation, see function documentation for details. */
415 }
416
418
419 if (use_all_regions) {
420 view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx);
421 }
422 else {
423 view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
424 }
425
426 ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
427
428 return OPERATOR_FINISHED;
429}
430
432{
433 /* identifiers */
434 ot->name = "Frame Selected";
435 ot->description = "Move the view to the selection center";
436 ot->idname = "VIEW3D_OT_view_selected";
437
438 /* api callbacks */
441
442 /* flags */
443 ot->flag = 0;
444
445 /* properties */
447}
448
std::optional< blender::Bounds< blender::float3 > > BKE_pose_minmax(const Object *ob, bool use_select)
Definition armature.cc:3088
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
#define FOREACH_OBJECT_IN_MODE_END
Definition BKE_layer.hh:382
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
#define FOREACH_OBJECT_IN_MODE_BEGIN(_scene, _view_layer, _v3d, _object_type, _object_mode, _instance)
Definition BKE_layer.hh:377
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3])
bool BKE_object_empty_image_frame_is_visible_in_view3d(const Object *ob, const RegionView3D *rv3d)
bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], bool use_hidden)
void BKE_paint_stroke_get_average(const Scene *scene, const Object *ob, float stroke[3])
Definition paint.cc:1850
bool BKE_paint_select_face_test(const Object *ob)
Definition paint.cc:1607
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
void minmax_v3v3_v3(float min[3], float max[3], const float vec[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(float r[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
#define INIT_MINMAX(min, max)
void DEG_id_tag_update(ID *id, unsigned int flags)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ViewLayer * DEG_get_evaluated_view_layer(const Depsgraph *graph)
Object * DEG_get_original_object(Object *object)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT
@ OB_MODE_SCULPT_CURVES
@ OB_MODE_POSE
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_VERTEX_PAINT
@ OB_EMPTY
@ OB_ARMATURE
@ OB_EMPTY_IMAGE
#define BASE_SELECTED(v3d, base)
#define BASE_SELECTED_EDITABLE(v3d, base)
#define BASE_VISIBLE(v3d, base)
@ RGN_TYPE_WINDOW
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
@ V3D_LOCK_CAMERA
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
Definition editface.cc:717
int PE_minmax(Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, blender::float3 &min, blender::float3 &max)
bool ED_operator_region_view3d_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
#define VIEW3D_MARGIN
float ED_view3d_radius_to_dist(const View3D *v3d, const ARegion *region, const Depsgraph *depsgraph, char persp, bool use_aspect, float radius)
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
const Depsgraph * depsgraph
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
#define min(a, b)
Definition sort.c:32
struct Base * next
struct Object * object
struct ID * orig_id
Definition DNA_ID.h:466
char empty_drawtype
const char * undo_str
struct Object * camera
float clip_start
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct wmOperatorType * type
struct PointerRNA * ptr
float max
bool ED_view3d_minmax_verts(const Scene *scene, Object *obedit, float min[3], float max[3])
void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag)
bool view3d_zoom_or_dolly_poll(bContext *C)
void ED_view3d_smooth_view_undo_begin(bContext *C, const ScrArea *area)
void ED_view3d_smooth_view(bContext *C, View3D *v3d, ARegion *region, int smooth_viewtx, const V3D_SmoothParams *sview)
@ V3D_OP_PROP_USE_ALL_REGIONS
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
void ED_view3d_smooth_view_undo_end(bContext *C, const ScrArea *area, const char *undo_str, bool undo_grouped)
static void view3d_from_minmax_multi(bContext *C, View3D *v3d, const float min[3], const float max[3], const bool ok_dist, const int smooth_viewtx)
static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *region, const float min[3], const float max[3], bool ok_dist, const int smooth_viewtx)
static int viewselected_exec(bContext *C, wmOperator *op)
static bool view3d_object_skip_minmax(const View3D *v3d, const RegionView3D *rv3d, const Object *ob, const bool skip_camera, bool *r_only_center)
static int view3d_all_exec(bContext *C, wmOperator *op)
static void view3d_object_calc_minmax(Depsgraph *depsgraph, Scene *scene, Object *ob_eval, const bool only_center, float min[3], float max[3])
void VIEW3D_OT_view_all(wmOperatorType *ot)
void VIEW3D_OT_view_selected(wmOperatorType *ot)
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap, bool, bool use_select, float r_min[3], float r_max[3])
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
int WM_operator_smooth_viewtx_get(const wmOperator *op)