Blender V5.0
view3d_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <algorithm>
12#include <cfloat>
13#include <cmath>
14#include <cstdio>
15#include <cstring>
16
17#include "DNA_camera_types.h"
18#include "DNA_curve_types.h"
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21#include "DNA_world_types.h"
22
23#include "RNA_path.hh"
24
25#include "MEM_guardedalloc.h"
26
27#include "BLI_array_utils.h"
28#include "BLI_bitmap_draw_2d.h"
29#include "BLI_listbase.h"
30#include "BLI_math_color.h"
31#include "BLI_math_geom.h"
32#include "BLI_math_matrix.h"
33#include "BLI_math_rotation.h"
34#include "BLI_math_vector.h"
35#include "BLI_rect.h"
36#include "BLI_utildefines.h"
37#include "BLI_vector.hh"
38
39#include "BKE_camera.h"
40#include "BKE_context.hh"
41#include "BKE_library.hh"
42#include "BKE_object.hh"
43#include "BKE_scene.hh"
44#include "BKE_screen.hh"
45
46#include "DEG_depsgraph.hh"
48
49#include "GPU_matrix.hh"
50
51#include "WM_api.hh"
52#include "WM_types.hh"
53
54#include "ED_keyframing.hh"
55#include "ED_screen.hh"
56#include "ED_undo.hh"
57#include "ED_view3d.hh"
58
59#include "ANIM_keyframing.hh"
60#include "ANIM_keyingsets.hh"
61
62#include "UI_resources.hh"
63
64#include "view3d_intern.hh" /* own include */
65
66/* -------------------------------------------------------------------- */
69
70void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
71{
73 if (scene->world) {
74 copy_v3_v3(r_color, &scene->world->horr);
75 return;
76 }
77 }
79 copy_v3_v3(r_color, v3d->shading.background_color);
80 return;
81 }
82
84}
85
87 const View3D *v3d,
88 float r_text_color[4],
89 float r_shadow_color[4])
90{
91 /* Text fully opaque, shadow slightly transparent. */
92 r_text_color[3] = 1.0f;
93 r_shadow_color[3] = 0.8f;
94
95 /* Default text color from TH_TEXT_HI. If it is too close
96 * to the background color, darken or lighten it. */
97 UI_GetThemeColor3fv(TH_TEXT_HI, r_text_color);
98 float text_lightness = srgb_to_grayscale(r_text_color);
99 float bg_color[3];
100 ED_view3d_background_color_get(scene, v3d, bg_color);
101 const float distance = len_v3v3(r_text_color, bg_color);
102 if (distance < 0.5f) {
103 if (text_lightness > 0.5f) {
104 mul_v3_fl(r_text_color, 0.33f);
105 }
106 else {
107 mul_v3_fl(r_text_color, 3.0f);
108 }
109 clamp_v3(r_text_color, 0.0f, 1.0f);
110 }
111
112 /* Shadow color is black or white depending on final text lightness. */
113 text_lightness = srgb_to_grayscale(r_text_color);
114 if (text_lightness > 0.4f) {
115 copy_v3_fl(r_shadow_color, 0.0f);
116 }
117 else {
118 copy_v3_fl(r_shadow_color, 1.0f);
119 }
120}
121
123 const Object *ob,
124 const View3D *v3d)
125{
126 if (v3d->shading.type == OB_SOLID) {
128 return true;
129 }
130 if (ob && ob->mode == OB_MODE_TEXTURE_PAINT) {
131 return true;
132 }
133 }
134 else if (v3d->shading.type == OB_RENDER) {
137 }
138 }
139 return false;
140}
141
143{
144 /* establish the camera object,
145 * so we can default to view mapping if anything is wrong with it */
146 if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
147 return static_cast<Camera *>(v3d->camera->data);
148 }
149 return nullptr;
150}
151
152float ED_view3d_dist_soft_min_get(const View3D *v3d, const bool use_persp_range)
153{
154 return use_persp_range ? (v3d->clip_start * 1.5f) : v3d->grid * 0.001f;
155}
156
157blender::Bounds<float> ED_view3d_dist_soft_range_get(const View3D *v3d, const bool use_persp_range)
158{
159 return {
160 ED_view3d_dist_soft_min_get(v3d, use_persp_range),
161 v3d->clip_end * 10.0f,
162 };
163}
164
166 const View3D *v3d,
167 const RegionView3D *rv3d,
168 const bool use_ortho_factor,
169 float *r_clip_start,
170 float *r_clip_end)
171{
173
176
177 if (use_ortho_factor && params.is_ortho) {
178 const float fac = 2.0f / (params.clip_end - params.clip_start);
179 params.clip_start *= fac;
180 params.clip_end *= fac;
181 }
182
183 if (r_clip_start) {
184 *r_clip_start = params.clip_start;
185 }
186 if (r_clip_end) {
187 *r_clip_end = params.clip_end;
188 }
189
190 return params.is_ortho;
191}
192
193bool ED_view3d_viewplane_get(const Depsgraph *depsgraph,
194 const View3D *v3d,
195 const RegionView3D *rv3d,
196 int winx,
197 int winy,
198 rctf *r_viewplane,
199 float *r_clip_start,
200 float *r_clip_end,
201 float *r_pixsize)
202{
204
207 BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
208
209 if (r_viewplane) {
210 *r_viewplane = params.viewplane;
211 }
212 if (r_clip_start) {
213 *r_clip_start = params.clip_start;
214 }
215 if (r_clip_end) {
216 *r_clip_end = params.clip_end;
217 }
218 if (r_pixsize) {
219 *r_pixsize = params.viewdx;
220 }
221
222 return params.is_ortho;
223}
224
226
227/* -------------------------------------------------------------------- */
230
232{
233 ARegion *region = CTX_wm_region(C);
234
236}
237
239{
240 /* for debugging purpose, context should always be OK */
241 if ((region == nullptr) || (region->regiontype != RGN_TYPE_WINDOW)) {
242 printf("view3d_region_operator_needs_gpu error, wrong region\n");
243 }
244 else {
245 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
246
247 wmViewport(&region->winrct); /* TODO: bad */
249 GPU_matrix_set(rv3d->viewmat);
250 }
251}
252
253void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
254{
255 if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
256 return;
257 }
258
259 float viewdist = rv3d->dist;
260
261 /* Special exception for orthographic camera (`viewdist` isn't used for perspective cameras). */
262 if (dist != 0.0f) {
263 if (rv3d->persp == RV3D_CAMOB) {
264 if (rv3d->is_persp == false) {
265 viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
266 }
267 }
268 }
269
270 GPU_polygon_offset(viewdist, dist);
271}
272
274{
275 bScreen *screen = CTX_wm_screen(C);
276 ScrArea *area = CTX_wm_area(C);
277
278 /* area can be nullptr when called from python */
279 if (area == nullptr || area->spacetype != SPACE_VIEW3D) {
280 area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
281 }
282
283 if (area == nullptr) {
284 return false;
285 }
286
288 if (region == nullptr) {
289 return false;
290 }
291
292 /* Bad context switch. */
293 CTX_wm_area_set(C, area);
294 CTX_wm_region_set(C, region);
295
296 return true;
297}
298
300
301/* -------------------------------------------------------------------- */
304
306 const BoundBox *bb,
307 const bool is_flip)
308{
309 for (int val = 0; val < 4; val++) {
310 normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
311 if (UNLIKELY(is_flip)) {
312 negate_v3(clip[val]);
313 }
314
315 clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
316 }
317}
318
320 BoundBox *bb, float planes[4][4], const ARegion *region, const Object *ob, const rcti *rect)
321{
322 /* init in case unproject fails */
323 memset(bb->vec, 0, sizeof(bb->vec));
324
325 /* four clipping planes and bounding volume */
326 /* first do the bounding volume */
327 for (int val = 0; val < 4; val++) {
328 float xs = ELEM(val, 0, 3) ? rect->xmin : rect->xmax;
329 float ys = ELEM(val, 0, 1) ? rect->ymin : rect->ymax;
330
331 ED_view3d_unproject_v3(region, xs, ys, 0.0, bb->vec[val]);
332 ED_view3d_unproject_v3(region, xs, ys, 1.0, bb->vec[4 + val]);
333 }
334
335 /* optionally transform to object space */
336 if (ob) {
337 float imat[4][4];
338 invert_m4_m4(imat, ob->object_to_world().ptr());
339
340 for (int val = 0; val < 8; val++) {
341 mul_m4_v3(imat, bb->vec[val]);
342 }
343 }
344
345 /* verify if we have negative scale. doing the transform before cross
346 * product flips the sign of the vector compared to doing cross product
347 * before transform then, so we correct for that. */
348 int flip_sign = (ob) ? is_negative_m4(ob->object_to_world().ptr()) : false;
349
350 ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
351}
352
354
355/* -------------------------------------------------------------------- */
358
360 float min[3];
361 float max[3];
362};
363
365 const float co[3], int /*i*/, int /*j*/, int /*k*/, void *user_data_p)
366{
368 user_data_p);
369 minmax_v3v3_v3(user_data->min, user_data->max, co);
370}
371
372bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
373{
374 /* 6 planes for the cube, 4..6 for the current view clipping planes. */
375 float planes[6 + 6][4];
376
377 /* Convert the min/max to 6 planes. */
378 for (int i = 0; i < 3; i++) {
379 float *plane_min = planes[(i * 2) + 0];
380 float *plane_max = planes[(i * 2) + 1];
381 zero_v3(plane_min);
382 zero_v3(plane_max);
383 plane_min[i] = -1.0f;
384 plane_min[3] = +min[i];
385 plane_max[i] = +1.0f;
386 plane_max[3] = -max[i];
387 }
388
389 /* Copy planes from the viewport & flip. */
390 int planes_len = 6;
391 int clip_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6;
392 for (int i = 0; i < clip_len; i++) {
393 negate_v4_v4(planes[planes_len], rv3d->clip[i]);
394 planes_len += 1;
395 }
396
397 /* Calculate points intersecting all planes (effectively intersecting two bounding boxes). */
399 INIT_MINMAX(user_data.min, user_data.max);
400
401 const float eps_coplanar = 1e-4f;
402 const float eps_isect = 1e-6f;
404 planes, planes_len, eps_coplanar, eps_isect, points_in_planes_minmax_fn, &user_data))
405 {
406 copy_v3_v3(min, user_data.min);
407 copy_v3_v3(max, user_data.max);
408 return true;
409 }
410 return false;
411}
412
414
415/* -------------------------------------------------------------------- */
418
419static bool view3d_boundbox_clip_m4(const BoundBox *bb, const float persmatob[4][4])
420{
421 int a, flag = -1, fl;
422
423 for (a = 0; a < 8; a++) {
424 float vec[4], min, max;
425 copy_v3_v3(vec, bb->vec[a]);
426 vec[3] = 1.0;
427 mul_m4_v4(persmatob, vec);
428 max = vec[3];
429 min = -vec[3];
430
431 fl = 0;
432 if (vec[0] < min) {
433 fl += 1;
434 }
435 if (vec[0] > max) {
436 fl += 2;
437 }
438 if (vec[1] < min) {
439 fl += 4;
440 }
441 if (vec[1] > max) {
442 fl += 8;
443 }
444 if (vec[2] < min) {
445 fl += 16;
446 }
447 if (vec[2] > max) {
448 fl += 32;
449 }
450
451 flag &= fl;
452 if (flag == 0) {
453 return true;
454 }
455 }
456
457 return false;
458}
459
460bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
461{
462 /* return 1: draw */
463
464 float persmatob[4][4];
465
466 if (bb == nullptr) {
467 return true;
468 }
469
470 mul_m4_m4m4(persmatob, (float (*)[4])rv3d->persmat, obmat);
471
472 return view3d_boundbox_clip_m4(bb, persmatob);
473}
474
476{
477 if (bb == nullptr) {
478 return true;
479 }
480 return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
481}
482
484
485/* -------------------------------------------------------------------- */
490
492{
493 return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_center_cursor || v3d->ob_center);
494}
495
497{
498 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
499 rv3d->lview = rv3d->view;
500 rv3d->lview_axis_roll = rv3d->view_axis_roll;
501 if (rv3d->persp != RV3D_CAMOB) {
502 rv3d->lpersp = rv3d->persp;
503 }
504}
505
507{
508 v3d->ob_center = nullptr;
509 v3d->ob_center_bone[0] = '\0';
510 v3d->ob_center_cursor = false;
511
512 v3d->flag2 &= ~V3D_LOCK_CAMERA;
513}
514
516 View3D *v3d,
517 RegionView3D *rv3d,
518 const char persp)
519{
520 BLI_assert(rv3d->persp == RV3D_CAMOB);
521 BLI_assert(persp != RV3D_CAMOB);
522
523 if (v3d->camera) {
524 Object *ob_camera_eval = DEG_get_evaluated(depsgraph, v3d->camera);
526 ob_camera_eval->object_to_world().ptr(), rv3d->ofs, VIEW3D_DIST_FALLBACK);
527 ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, nullptr);
529 }
530
531 if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
532 rv3d->persp = persp;
533 }
534}
535bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
536{
537 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
538 const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
539
541
542 if (ED_view3d_camera_lock_check(v3d, rv3d)) {
543 return false;
544 }
545
546 if (rv3d->persp != RV3D_PERSP) {
547 if (rv3d->persp == RV3D_CAMOB) {
548 /* If autopersp and previous view was an axis one,
549 * switch back to PERSP mode, else reuse previous mode. */
550 char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? char(RV3D_PERSP) : rv3d->lpersp;
552 }
553 else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
554 rv3d->persp = RV3D_PERSP;
555 }
556 return true;
557 }
558
559 return false;
560}
561
563
564/* -------------------------------------------------------------------- */
569
570bool ED_view3d_camera_view_zoom_scale(RegionView3D *rv3d, const float scale)
571{
572 const float camzoom_init = rv3d->camzoom;
573 float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
574 /* Clamp both before and after conversion to prevent NAN on negative values. */
575
576 zoomfac = zoomfac * scale;
580 return (rv3d->camzoom != camzoom_init);
581}
582
583bool ED_view3d_camera_view_pan(ARegion *region, const float event_ofs[2])
584{
585 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
586 const float camdxy_init[2] = {rv3d->camdx, rv3d->camdy};
587 const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
588 rv3d->camdx += event_ofs[0] / (region->winx * zoomfac);
589 rv3d->camdy += event_ofs[1] / (region->winy * zoomfac);
590 CLAMP(rv3d->camdx, -1.0f, 1.0f);
591 CLAMP(rv3d->camdy, -1.0f, 1.0f);
592 return (camdxy_init[0] != rv3d->camdx) || (camdxy_init[1] != rv3d->camdy);
593}
594
596
597/* -------------------------------------------------------------------- */
602
604{
605 return ((v3d->camera) && ID_IS_EDITABLE(v3d->camera) && (v3d->flag2 & V3D_LOCK_CAMERA) &&
606 (rv3d->persp == RV3D_CAMOB));
607}
608
610 View3D *v3d,
611 RegionView3D *rv3d,
612 const bool calc_dist)
613{
614 if (ED_view3d_camera_lock_check(v3d, rv3d)) {
615 Object *ob_camera_eval = DEG_get_evaluated(depsgraph, v3d->camera);
616 if (calc_dist) {
617 /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
619 ob_camera_eval->object_to_world().ptr(), rv3d->ofs, VIEW3D_DIST_FALLBACK);
620 }
621 ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, nullptr);
622 }
623}
624
625void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
626{
628}
629
630bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
631{
632 if (ED_view3d_camera_lock_check(v3d, rv3d)) {
634 Object *root_parent;
635
637 (root_parent = v3d->camera->parent))
638 {
639 Object *ob_update;
640 float tmat[4][4];
641 float imat[4][4];
642 float view_mat[4][4];
643 float diff_mat[4][4];
644 float parent_mat[4][4];
645
646 while (root_parent->parent) {
647 root_parent = root_parent->parent;
648 }
649 Object *ob_camera_eval = DEG_get_evaluated(depsgraph, v3d->camera);
650 Object *root_parent_eval = DEG_get_evaluated(depsgraph, root_parent);
651
652 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
653
654 normalize_m4_m4(tmat, ob_camera_eval->object_to_world().ptr());
655
656 invert_m4_m4(imat, tmat);
657 mul_m4_m4m4(diff_mat, view_mat, imat);
658
659 mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->object_to_world().ptr());
660
661 BKE_object_tfm_protected_backup(root_parent, &obtfm);
662 BKE_object_apply_mat4(root_parent, parent_mat, true, false);
663 BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
664
665 ob_update = v3d->camera;
666 while (ob_update) {
669 ob_update = ob_update->parent;
670 }
671 }
672 else {
673 /* always maintain the same scale */
674 const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
676 ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
678 v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
679
682 }
683
684 return true;
685 }
686 return false;
687}
688
690 const Scene *scene, ID *id_key, bContext *C, const bool do_rotate, const bool do_translate)
691{
692 BLI_assert(GS(id_key->name) == ID_OB);
693 using namespace blender;
694
695 /* While `autokeyframe_object` does already call `autokeyframe_cfra_can_key` we need this here
696 * because at the time of writing this it returns void. Once the keying result is returned, like
697 * implemented for `blender::animrig::insert_keyframes`, this `if` can be removed. */
698 if (!animrig::autokeyframe_cfra_can_key(scene, id_key)) {
699 return false;
700 }
701
702 Object *camera_object = reinterpret_cast<Object *>(id_key);
703
704 Vector<RNAPath> rna_paths;
705
706 if (do_rotate) {
707 switch (camera_object->rotmode) {
708 case ROT_MODE_QUAT:
709 rna_paths.append({"rotation_quaternion"});
710 break;
711
713 rna_paths.append({"rotation_axis_angle"});
714 break;
715
716 case ROT_MODE_EUL:
717 rna_paths.append({"rotation_euler"});
718 break;
719
720 default:
721 break;
722 }
723 }
724 if (do_translate) {
725 rna_paths.append({"location"});
726 }
727
728 animrig::autokeyframe_object(C, scene, camera_object, rna_paths);
730 return true;
731}
732
734 View3D *v3d, RegionView3D *rv3d, bContext *C, const bool do_rotate, const bool do_translate)
735{
736 /* similar to ED_view3d_cameracontrol_update */
737 if (ED_view3d_camera_lock_check(v3d, rv3d)) {
738 Scene *scene = CTX_data_scene(C);
739 ID *id_key;
740 Object *root_parent;
742 (root_parent = v3d->camera->parent))
743 {
744 while (root_parent->parent) {
745 root_parent = root_parent->parent;
746 }
747 id_key = &root_parent->id;
748 }
749 else {
750 id_key = &v3d->camera->id;
751 }
752
753 return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
754 }
755 return false;
756}
757
759{
760 if (ED_view3d_camera_lock_check(v3d, rv3d)) {
762 return true;
763 }
764 }
765 return false;
766}
767
776static bool view3d_camera_lock_undo_ex(const char *str,
777 const View3D *v3d,
778 const RegionView3D *rv3d,
779 bContext *C,
780 const bool undo_group)
781{
782 if (ED_view3d_camera_lock_undo_test(v3d, rv3d, C)) {
783 if (undo_group) {
785 }
786 else {
788 }
789 return true;
790 }
791 return false;
792}
793
795 const View3D *v3d,
796 const RegionView3D *rv3d,
797 bContext *C)
798{
799 return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, false);
800}
801
803 const View3D *v3d,
804 const RegionView3D *rv3d,
805 bContext *C)
806{
807 return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, true);
808}
809
811
812/* -------------------------------------------------------------------- */
817
818static void view3d_boxview_clip(ScrArea *area)
819{
820 BoundBox *bb = MEM_callocN<BoundBox>("clipbb");
821 float clip[6][4];
822 float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
823
824 /* create bounding box */
825 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
826 if (region->regiontype == RGN_TYPE_WINDOW) {
827 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
828
829 if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
831 if (region->winx > region->winy) {
832 x1 = rv3d->dist;
833 }
834 else {
835 x1 = region->winx * rv3d->dist / region->winy;
836 }
837
838 if (region->winx > region->winy) {
839 y1 = region->winy * rv3d->dist / region->winx;
840 }
841 else {
842 y1 = rv3d->dist;
843 }
844 copy_v2_v2(ofs, rv3d->ofs);
845 }
846 else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
847 ofs[2] = rv3d->ofs[2];
848
849 if (region->winx > region->winy) {
850 z1 = region->winy * rv3d->dist / region->winx;
851 }
852 else {
853 z1 = rv3d->dist;
854 }
855 }
856 }
857 }
858 }
859
860 for (int val = 0; val < 8; val++) {
861 if (ELEM(val, 0, 3, 4, 7)) {
862 bb->vec[val][0] = -x1 - ofs[0];
863 }
864 else {
865 bb->vec[val][0] = x1 - ofs[0];
866 }
867
868 if (ELEM(val, 0, 1, 4, 5)) {
869 bb->vec[val][1] = -y1 - ofs[1];
870 }
871 else {
872 bb->vec[val][1] = y1 - ofs[1];
873 }
874
875 if (val > 3) {
876 bb->vec[val][2] = -z1 - ofs[2];
877 }
878 else {
879 bb->vec[val][2] = z1 - ofs[2];
880 }
881 }
882
883 /* normals for plane equations */
884 normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
885 normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
886 normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
887 normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
888 normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
889 normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
890
891 /* then plane equations */
892 for (int val = 0; val < 6; val++) {
893 clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
894 }
895
896 /* create bounding box */
897 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
898 if (region->regiontype == RGN_TYPE_WINDOW) {
899 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
900
901 if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
902 rv3d->rflag |= RV3D_CLIPPING;
903 memcpy(rv3d->clip, clip, sizeof(clip));
904 if (rv3d->clipbb) {
905 MEM_freeN(rv3d->clipbb);
906 }
907 rv3d->clipbb = static_cast<BoundBox *>(MEM_dupallocN(bb));
908 }
909 }
910 }
911 MEM_freeN(bb);
912}
913
918static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
919{
920 /* absolute axis values above this are considered to be set (will be ~1.0f) */
921 const float axis_eps = 0.5f;
922 float viewinv[4];
923
924 /* use the view rotation to identify which axis to sync on */
925 float view_axis_all[4][3] = {
926 {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}};
927
928 float *view_src_x = &view_axis_all[0][0];
929 float *view_src_y = &view_axis_all[1][0];
930
931 float *view_dst_x = &view_axis_all[2][0];
932 float *view_dst_y = &view_axis_all[3][0];
933 int i;
934
935 /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
936 if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, rv3d_src->view_axis_roll, viewinv) ==
937 false))
938 {
939 return;
940 }
941 invert_qt_normalized(viewinv);
942 mul_qt_v3(viewinv, view_src_x);
943 mul_qt_v3(viewinv, view_src_y);
944
945 if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, rv3d_dst->view_axis_roll, viewinv) ==
946 false))
947 {
948 return;
949 }
950 invert_qt_normalized(viewinv);
951 mul_qt_v3(viewinv, view_dst_x);
952 mul_qt_v3(viewinv, view_dst_y);
953
954 /* Check source and destination have a matching axis. */
955 for (i = 0; i < 3; i++) {
956 if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
957 ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
958 {
959 rv3d_dst->ofs[i] = rv3d_src->ofs[i];
960 }
961 }
962}
963
965{
966 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
967 short clip = 0;
968
969 LISTBASE_FOREACH (ARegion *, region_test, &area->regionbase) {
970 if (region_test != region && region_test->regiontype == RGN_TYPE_WINDOW) {
971 RegionView3D *rv3dtest = static_cast<RegionView3D *>(region_test->regiondata);
972
973 if (RV3D_LOCK_FLAGS(rv3dtest) & RV3D_LOCK_ROTATION) {
974 rv3dtest->dist = rv3d->dist;
975 view3d_boxview_sync_axis(rv3dtest, rv3d);
976 clip |= RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP;
977
978 ED_region_tag_redraw(region_test);
979 }
980 }
981 }
982
983 if (clip) {
985 }
986}
987
989{
990 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
991 bool clip = false;
992
993 LISTBASE_FOREACH (ARegion *, region_test, &area->regionbase) {
994 if (region_test != region && region_test->regiontype == RGN_TYPE_WINDOW) {
995 RegionView3D *rv3dtest = static_cast<RegionView3D *>(region_test->regiondata);
996
997 if (RV3D_LOCK_FLAGS(rv3dtest)) {
998 rv3dtest->dist = rv3d->dist;
999 copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
1000 ED_region_tag_redraw(region_test);
1001
1002 clip |= ((RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP) != 0);
1003 }
1004 }
1005 }
1006
1007 if (clip) {
1008 view3d_boxview_clip(area);
1009 }
1010}
1011
1012void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
1013{
1014 ARegion *region_sync = nullptr;
1015 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1016 /* this function copies flags from the first of the 3 other quadview
1017 * regions to the 2 other, so it assumes this is the region whose
1018 * properties are always being edited, weak */
1019 short viewlock = rv3d->viewlock;
1020
1021 if ((viewlock & RV3D_LOCK_ROTATION) == 0) {
1022 do_clip = (viewlock & RV3D_BOXCLIP) != 0;
1023 viewlock = 0;
1024 }
1025 else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
1026 do_clip = true;
1027 viewlock &= ~RV3D_BOXCLIP;
1028 }
1029
1030 for (; region; region = region->prev) {
1031 if (region->alignment == RGN_ALIGN_QSPLIT) {
1032 rv3d = static_cast<RegionView3D *>(region->regiondata);
1033 rv3d->viewlock = viewlock;
1034
1035 if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
1036 rv3d->rflag &= ~RV3D_BOXCLIP;
1037 }
1038
1039 /* use region_sync so we sync with one of the aligned views below
1040 * else the view jumps on changing view settings like 'clip'
1041 * since it copies from the perspective view */
1042 region_sync = region;
1043 }
1044 }
1045
1046 if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
1048 static_cast<ARegion *>(region_sync ? region_sync : area->regionbase.last));
1049 }
1050
1051 /* ensure locked regions have an axis, locked user views don't make much sense */
1052 if (viewlock & RV3D_LOCK_ROTATION) {
1053 int index_qsplit = 0;
1054 LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
1055 if (region_iter->alignment == RGN_ALIGN_QSPLIT) {
1056 rv3d = static_cast<RegionView3D *>(region_iter->regiondata);
1057 if (rv3d->viewlock) {
1058 if (!RV3D_VIEW_IS_AXIS(rv3d->view) || (rv3d->view_axis_roll != RV3D_VIEW_AXIS_ROLL_0)) {
1059 rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
1061 rv3d->persp = RV3D_ORTHO;
1062 ED_view3d_lock(rv3d);
1063 }
1064 }
1065 index_qsplit++;
1066 }
1067 }
1068 }
1069
1070 ED_area_tag_redraw(area);
1071}
1072
1074
1075/* -------------------------------------------------------------------- */
1081
1082static const char *view3d_autodepth_last_id = "view3d_autodist_last";
1083
1088 float ofs[3];
1090};
1091
1093{
1094 if (event->flag & WM_EVENT_IS_CONSECUTIVE) {
1095 const View3D_AutoDistLast *autodepth_last = static_cast<const View3D_AutoDistLast *>(
1097 if (autodepth_last) {
1098 return true;
1099 }
1100 }
1101 return false;
1102}
1103
1108
1110 const wmEvent *event,
1111 const float ofs[3],
1112 const bool has_depth)
1113{
1115
1117 View3D_AutoDistLast *autodepth_last = static_cast<View3D_AutoDistLast *>(
1118 MEM_callocN(sizeof(*autodepth_last), __func__));
1119
1120 autodepth_last->has_depth = has_depth;
1121 copy_v3_v3(autodepth_last->ofs, ofs);
1122
1124 }
1125}
1126
1127bool ED_view3d_autodist_last_get(wmWindow *win, float r_ofs[3])
1128{
1129 const View3D_AutoDistLast *autodepth_last = static_cast<const View3D_AutoDistLast *>(
1131 /* #ED_view3d_autodist_last_check should be called first. */
1132 BLI_assert(autodepth_last);
1133 if (autodepth_last == nullptr) {
1134 return false;
1135 }
1136
1137 if (autodepth_last->has_depth == false) {
1138 zero_v3(r_ofs);
1139 return false;
1140 }
1141 copy_v3_v3(r_ofs, autodepth_last->ofs);
1142 return true;
1143}
1144
1146
1147/* -------------------------------------------------------------------- */
1150
1151static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin)
1152{
1153 rcti rect;
1154 if (margin == 0) {
1155 /* Get Z Depths, needed for perspective, nice for ortho */
1156 rect.xmin = mval[0];
1157 rect.ymin = mval[1];
1158 rect.xmax = mval[0] + 1;
1159 rect.ymax = mval[1] + 1;
1160 }
1161 else {
1162 BLI_rcti_init_pt_radius(&rect, mval, margin);
1163 }
1164
1165 ViewDepths depth_temp = {0};
1166 view3d_depths_rect_create(region, &rect, &depth_temp);
1167 float depth_close = view3d_depth_near(&depth_temp);
1168 MEM_SAFE_FREE(depth_temp.depths);
1169 return depth_close;
1170}
1171
1173 View3D *v3d,
1174 const int mval[2],
1175 float mouse_worldloc[3],
1176 const float fallback_depth_pt[3])
1177{
1178 float depth_close;
1179 int margin_arr[] = {0, 2, 4};
1180 bool depth_ok = false;
1181
1182 /* Attempt with low margin's first */
1183 int i = 0;
1184 do {
1185 depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize);
1186 depth_ok = (depth_close != FLT_MAX);
1187 } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
1188
1189 if (depth_ok) {
1190 float centx = float(mval[0]) + 0.5f;
1191 float centy = float(mval[1]) + 0.5f;
1192
1193 if (ED_view3d_unproject_v3(region, centx, centy, depth_close, mouse_worldloc)) {
1194 return true;
1195 }
1196 }
1197
1198 if (fallback_depth_pt) {
1199 ED_view3d_win_to_3d_int(v3d, region, fallback_depth_pt, mval, mouse_worldloc);
1200 return true;
1201 }
1202 return false;
1203}
1204
1206 const int mval[2],
1207 float mouse_worldloc[3],
1208 int margin,
1209 const float *force_depth)
1210{
1211 /* Get Z Depths, needed for perspective, nice for ortho */
1212 float depth;
1213 if (force_depth) {
1214 depth = *force_depth;
1215 }
1216 else {
1217 depth = view_autodist_depth_margin(region, mval, margin);
1218 }
1219
1220 if (depth == FLT_MAX) {
1221 return false;
1222 }
1223
1224 float centx = float(mval[0]) + 0.5f;
1225 float centy = float(mval[1]) + 0.5f;
1226 return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc);
1227}
1228
1229static bool depth_segment_cb(int x, int y, void *user_data)
1230{
1231 struct UserData {
1232 const ViewDepths *vd;
1233 int margin;
1234 float depth;
1235 } *data = static_cast<UserData *>(user_data);
1236 int mval[2];
1237 float depth;
1238
1239 mval[0] = x;
1240 mval[1] = y;
1241
1242 if (ED_view3d_depth_read_cached(data->vd, mval, data->margin, &depth)) {
1243 data->depth = depth;
1244 return false;
1245 }
1246 return true;
1247}
1248
1250 const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *r_depth)
1251{
1252 struct {
1253 const ViewDepths *vd;
1254 int margin;
1255 float depth;
1256 } data = {nullptr};
1257 int p1[2];
1258 int p2[2];
1259
1260 data.vd = vd;
1261 data.margin = margin;
1262 data.depth = 1.0f;
1263
1264 copy_v2_v2_int(p1, mval_sta);
1265 copy_v2_v2_int(p2, mval_end);
1266
1268
1269 *r_depth = data.depth;
1270
1271 return (*r_depth != 1.0f);
1272}
1273
1275
1276/* -------------------------------------------------------------------- */
1281
1282float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
1283{
1284 return radius * (1.0f / tanf(angle / 2.0f));
1285}
1286
1287float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
1288{
1289 return radius / (DEFAULT_SENSOR_WIDTH / lens);
1290}
1291
1293 const ARegion *region,
1294 const Depsgraph *depsgraph,
1295 const char persp,
1296 const bool use_aspect,
1297 const float radius)
1298{
1299 float dist;
1300
1302 BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
1303
1304 if (persp == RV3D_ORTHO) {
1305 dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
1306 }
1307 else {
1308 float lens, sensor_size, zoom;
1309
1310 if (persp == RV3D_CAMOB) {
1313 params.clip_start = v3d->clip_start;
1314 params.clip_end = v3d->clip_end;
1315 Object *camera_eval = DEG_get_evaluated(depsgraph, v3d->camera);
1317
1318 lens = params.lens;
1319 sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
1320
1321 /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
1323 }
1324 else {
1325 lens = v3d->lens;
1326 sensor_size = DEFAULT_SENSOR_WIDTH;
1328 }
1329
1330 float angle = focallength_to_fov(lens, sensor_size);
1331
1332 /* zoom influences lens, correct this by scaling the angle as a distance
1333 * (by the zoom-level) */
1334 angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
1335
1336 dist = ED_view3d_radius_to_dist_persp(angle, radius);
1337 }
1338
1339 if (use_aspect) {
1340 const RegionView3D *rv3d = static_cast<const RegionView3D *>(region->regiondata);
1341
1342 float winx, winy;
1343
1344 if (persp == RV3D_CAMOB) {
1345 /* camera frame x/y in pixels */
1346 winx = region->winx / rv3d->viewcamtexcofac[0];
1347 winy = region->winy / rv3d->viewcamtexcofac[1];
1348 }
1349 else {
1350 winx = region->winx;
1351 winy = region->winy;
1352 }
1353
1354 if (winx && winy) {
1355 float aspect = winx / winy;
1356 if (aspect < 1.0f) {
1357 aspect = 1.0f / aspect;
1358 }
1359 dist *= aspect;
1360 }
1361 }
1362
1363 return dist;
1364}
1365
1367
1368/* -------------------------------------------------------------------- */
1371
1372float ED_view3d_offset_distance(const float mat[4][4],
1373 const float ofs[3],
1374 const float fallback_dist)
1375{
1376 float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1377 float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1378
1379 mul_m4_v4(mat, pos);
1380 add_v3_v3(pos, ofs);
1381 mul_m4_v4(mat, dir);
1382 normalize_v3(dir);
1383
1384 float dist = dot_v3v3(pos, dir);
1385
1386 if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
1387 dist = fallback_dist;
1388 }
1389
1390 return dist;
1391}
1392
1393void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
1394{
1395 float viewinv[4];
1396 float tvec[3];
1397
1398 BLI_assert(dist >= 0.0f);
1399
1400 copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
1401/* rv3d->viewinv isn't always valid */
1402#if 0
1403 mul_mat3_m4_v3(rv3d->viewinv, tvec);
1404#else
1405 invert_qt_qt_normalized(viewinv, rv3d->viewquat);
1406 mul_qt_v3(viewinv, tvec);
1407#endif
1408 sub_v3_v3(rv3d->ofs, tvec);
1409
1410 rv3d->dist = dist;
1411}
1412
1414 const float dist_co[3],
1415 const float dist_min)
1416{
1417 float viewinv[4];
1418 invert_qt_qt_normalized(viewinv, rv3d->viewquat);
1419
1420 float tvec[3] = {0.0f, 0.0f, -1.0f};
1421 mul_qt_v3(viewinv, tvec);
1422
1423 float dist_co_local[3];
1424 negate_v3_v3(dist_co_local, rv3d->ofs);
1425 sub_v3_v3v3(dist_co_local, dist_co, dist_co_local);
1426 const float delta = dot_v3v3(tvec, dist_co_local);
1427 const float dist_new = rv3d->dist + delta;
1428 if (dist_new >= dist_min) {
1429 madd_v3_v3fl(rv3d->ofs, tvec, -delta);
1430 rv3d->dist = dist_new;
1431 return true;
1432 }
1433 return false;
1434}
1435
1437
1438/* -------------------------------------------------------------------- */
1441
1445static float view3d_quat_axis[6][4][4] = {
1446 /* RV3D_VIEW_FRONT */
1447 {
1448 {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f},
1449 {0.5f, -0.5f, -0.5f, 0.5f},
1450 {0, 0, -M_SQRT1_2, M_SQRT1_2},
1451 {-0.5f, 0.5f, -0.5f, 0.5f},
1452 }, /* RV3D_VIEW_BACK */
1453 {
1454 {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2},
1455 {0.5f, 0.5f, -0.5f, -0.5f},
1456 {M_SQRT1_2, M_SQRT1_2, 0, 0},
1457 {0.5f, 0.5f, 0.5f, 0.5f},
1458 }, /* RV3D_VIEW_LEFT */
1459 {
1460 {0.5f, -0.5f, 0.5f, 0.5f},
1461 {0, -M_SQRT1_2, 0.0f, M_SQRT1_2},
1462 {-0.5f, -0.5f, -0.5f, 0.5f},
1463 {-M_SQRT1_2, 0, -M_SQRT1_2, 0},
1464 },
1465
1466 /* RV3D_VIEW_RIGHT */
1467 {
1468 {0.5f, -0.5f, -0.5f, -0.5f},
1469 {M_SQRT1_2, 0, -M_SQRT1_2, 0},
1470 {0.5f, 0.5f, -0.5f, 0.5f},
1471 {0, M_SQRT1_2, 0, M_SQRT1_2},
1472 }, /* RV3D_VIEW_TOP */
1473 {
1474 {1.0f, 0.0f, 0.0f, 0.0f},
1475 {M_SQRT1_2, 0, 0, M_SQRT1_2},
1476 {0, 0, 0, 1},
1477 {-M_SQRT1_2, 0, 0, M_SQRT1_2},
1478 }, /* RV3D_VIEW_BOTTOM */
1479 {
1480 {0.0f, -1.0f, 0.0f, 0.0f},
1481 {0, -M_SQRT1_2, -M_SQRT1_2, 0},
1482 {0, 0, -1, 0},
1483 {0, M_SQRT1_2, -M_SQRT1_2, 0},
1484 },
1485
1486};
1487
1488bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4])
1489{
1490 BLI_assert(view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270);
1491 if (RV3D_VIEW_IS_AXIS(view)) {
1492 copy_qt_qt(r_quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll]);
1493 return true;
1494 }
1495 return false;
1496}
1497
1498bool ED_view3d_quat_to_axis_view(const float quat[4],
1499 const float epsilon,
1500 char *r_view,
1501 char *r_view_axis_roll)
1502{
1503 *r_view = RV3D_VIEW_USER;
1504 *r_view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
1505
1506 /* Quaternion values are all unit length. */
1507
1508 if (epsilon < M_PI_4) {
1509 /* Under 45 degrees, just pick the closest value. */
1510 for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
1511 for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
1512 view_axis_roll++)
1513 {
1515 quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll])) < epsilon)
1516 {
1517 *r_view = view;
1518 *r_view_axis_roll = view_axis_roll;
1519 return true;
1520 }
1521 }
1522 }
1523 }
1524 else {
1525 /* Epsilon over 45 degrees, check all & find use the closest. */
1526 float delta_best = FLT_MAX;
1527 for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
1528 for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
1529 view_axis_roll++)
1530 {
1531 const float delta_test = fabsf(
1532 angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll]));
1533 if (delta_best > delta_test) {
1534 delta_best = delta_test;
1535 *r_view = view;
1536 *r_view_axis_roll = view_axis_roll;
1537 }
1538 }
1539 }
1540 if (*r_view != RV3D_VIEW_USER) {
1541 return true;
1542 }
1543 }
1544
1545 return false;
1546}
1547
1549 const float epsilon,
1550 char *r_view,
1551 char *r_view_axis_roll)
1552{
1553 const bool is_axis_view = ED_view3d_quat_to_axis_view(quat, epsilon, r_view, r_view_axis_roll);
1554 if (is_axis_view) {
1555 /* Reset `quat` to it's view axis, so axis-aligned views are always *exactly* aligned. */
1556 BLI_assert(*r_view != RV3D_VIEW_USER);
1557 ED_view3d_quat_from_axis_view(*r_view, *r_view_axis_roll, quat);
1558 }
1559 return is_axis_view;
1560}
1561
1563{
1564 switch (index) {
1565 case 0:
1566 return RV3D_VIEW_FRONT;
1567 case 1:
1568 return RV3D_VIEW_TOP;
1569 case 2:
1570 return RV3D_VIEW_RIGHT;
1571 default:
1572 return RV3D_VIEW_USER;
1573 }
1574}
1575
1577{
1578 switch (view) {
1579 case RV3D_VIEW_FRONT:
1580 return RV3D_VIEW_BACK;
1581 case RV3D_VIEW_BACK:
1582 return RV3D_VIEW_FRONT;
1583 case RV3D_VIEW_LEFT:
1584 return RV3D_VIEW_RIGHT;
1585 case RV3D_VIEW_RIGHT:
1586 return RV3D_VIEW_LEFT;
1587 case RV3D_VIEW_TOP:
1588 return RV3D_VIEW_BOTTOM;
1589 case RV3D_VIEW_BOTTOM:
1590 return RV3D_VIEW_TOP;
1591 }
1592
1593 return RV3D_VIEW_USER;
1594}
1595
1597{
1598 return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, rv3d->viewquat);
1599}
1600
1602
1603/* -------------------------------------------------------------------- */
1606
1607void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
1608{
1609 float nmat[3][3];
1610
1611 /* dist depends on offset */
1612 BLI_assert(dist == nullptr || ofs != nullptr);
1613
1614 copy_m3_m4(nmat, mat);
1615 normalize_m3(nmat);
1616
1617 /* Offset */
1618 if (ofs) {
1619 negate_v3_v3(ofs, mat[3]);
1620 }
1621
1622 /* Quat */
1623 if (quat) {
1624 mat3_normalized_to_quat(quat, nmat);
1626 }
1627
1628 if (ofs && dist) {
1629 madd_v3_v3fl(ofs, nmat[2], *dist);
1630 }
1631}
1632
1633void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
1634{
1635 const float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
1636 float dvec[3] = {0.0f, 0.0f, dist};
1637
1638 quat_to_mat4(mat, iviewquat);
1639 mul_mat3_m4_v3(mat, dvec);
1640 sub_v3_v3v3(mat[3], dvec, ofs);
1641}
1642
1644 const Object *ob, float ofs[3], float quat[4], const float *dist, float *lens)
1645{
1646 ED_view3d_from_m4(ob->object_to_world().ptr(), ofs, quat, dist);
1647
1648 if (lens) {
1650
1653 *lens = params.lens;
1654 }
1655}
1656
1657void ED_view3d_to_object(const Depsgraph *depsgraph,
1658 Object *ob,
1659 const float ofs[3],
1660 const float quat[4],
1661 const float dist)
1662{
1663 float mat[4][4];
1664 ED_view3d_to_m4(mat, ofs, quat, dist);
1665
1666 Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
1667 BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true);
1668}
1669
1671 Depsgraph *depsgraph,
1672 const Scene *scene,
1673 Object *camera_ob,
1674 float *r_clip_start,
1675 float *r_clip_end)
1676{
1677 Object *camera_ob_eval = DEG_get_evaluated(depsgraph, camera_ob);
1678 float co[3]; /* the new location to apply */
1679 float scale; /* only for ortho cameras */
1680
1682 depsgraph, scene, camera_ob_eval, co, &scale, r_clip_start, r_clip_end))
1683 {
1685 float obmat_new[4][4];
1686 bool is_ortho_camera = false;
1687
1688 if ((camera_ob_eval->type == OB_CAMERA) &&
1689 (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO))
1690 {
1691 ((Camera *)camera_ob->data)->ortho_scale = scale;
1692 is_ortho_camera = true;
1693 }
1694
1695 copy_m4_m4(obmat_new, camera_ob_eval->object_to_world().ptr());
1696 copy_v3_v3(obmat_new[3], co);
1697
1698 /* only touch location */
1699 BKE_object_tfm_protected_backup(camera_ob, &obtfm);
1700 BKE_object_apply_mat4(camera_ob, obmat_new, true, true);
1702
1703 /* notifiers */
1704 DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM);
1705 if (is_ortho_camera) {
1706 DEG_id_tag_update_ex(bmain, static_cast<ID *>(camera_ob->data), ID_RECALC_PARAMETERS);
1707 }
1708
1709 return true;
1710 }
1711
1712 return false;
1713}
1714
1716 Depsgraph *depsgraph,
1717 const Scene *scene,
1718 Object *camera_ob)
1719{
1720 return view3d_camera_to_view_selected_impl(bmain, depsgraph, scene, camera_ob, nullptr, nullptr);
1721}
1722
1724 Depsgraph *depsgraph,
1725 const Scene *scene,
1726 Object *camera_ob)
1727{
1728 float clip_start;
1729 float clip_end;
1731 bmain, depsgraph, scene, camera_ob, &clip_start, &clip_end))
1732 {
1733
1734 ((Camera *)camera_ob->data)->clip_start = clip_start;
1735 ((Camera *)camera_ob->data)->clip_end = clip_end;
1736
1737 /* TODO: Support update via #ID_RECALC_PARAMETERS. */
1738 Object *camera_ob_eval = DEG_get_evaluated(depsgraph, camera_ob);
1739 ((Camera *)camera_ob_eval->data)->clip_start = clip_start;
1740 ((Camera *)camera_ob_eval->data)->clip_end = clip_end;
1741
1742 return true;
1743 }
1744
1745 return false;
1746}
1747
1749
1750/* -------------------------------------------------------------------- */
1753
1754struct ReadData {
1757 float r_depth;
1758};
1759
1760static bool depth_read_test_fn(const void *value, void *userdata)
1761{
1762 ReadData *data = static_cast<ReadData *>(userdata);
1763 float depth = *(float *)value;
1764 data->r_depth = std::min(depth, data->r_depth);
1765
1766 if ((++data->count) >= data->count_max) {
1767 /* Outside the margin. */
1768 return true;
1769 }
1770 return false;
1771}
1772
1774 const int mval[2],
1775 int margin,
1776 float *r_depth)
1777{
1778 *r_depth = 1.0f;
1779
1780 if (!vd || !vd->depths) {
1781 return false;
1782 }
1783
1784 BLI_assert(1.0 <= vd->depth_range[1]);
1785 int x = mval[0];
1786 int y = mval[1];
1787 if (x < 0 || y < 0 || x >= vd->w || y >= vd->h) {
1788 return false;
1789 }
1790
1791 float depth = 1.0f;
1792 if (margin) {
1793 int shape[2] = {vd->w, vd->h};
1794 int pixel_count = (min_ii(x + margin + 1, shape[1]) - max_ii(x - margin, 0)) *
1795 (min_ii(y + margin + 1, shape[0]) - max_ii(y - margin, 0));
1796
1797 ReadData data;
1798 data.count = 0;
1799 data.count_max = pixel_count;
1800 data.r_depth = 1.0f;
1801
1802 /* TODO: No need to go spiral. */
1804 depth = data.r_depth;
1805 }
1806 else {
1807 depth = vd->depths[y * vd->w + x];
1808 }
1809
1810 if (depth != 1.0f) {
1811 *r_depth = depth;
1812 return true;
1813 }
1814
1815 return false;
1816}
1817
1819 const ViewDepths *depths,
1820 const int mval[2],
1821 float r_normal[3])
1822{
1823 /* NOTE: we could support passing in a radius.
1824 * For now just read 9 pixels. */
1825
1826 /* pixels surrounding */
1827 bool depths_valid[9] = {false};
1828 float coords[9][3] = {{0}};
1829
1830 for (int x = 0, i = 0; x < 2; x++) {
1831 for (int y = 0; y < 2; y++) {
1832 const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
1833
1834 float depth_fl = 1.0f;
1835 ED_view3d_depth_read_cached(depths, mval_ofs, 0, &depth_fl);
1836 const double depth = double(depth_fl);
1837 if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
1838 if (ED_view3d_depth_unproject_v3(region, mval_ofs, depth, coords[i])) {
1839 depths_valid[i] = true;
1840 }
1841 }
1842 i++;
1843 }
1844 }
1845
1846 const int edges[2][6][2] = {
1847 /* x edges */
1848 {{0, 1}, {1, 2}, {3, 4}, {4, 5}, {6, 7}, {7, 8}}, /* y edges */
1849 {{0, 3}, {3, 6}, {1, 4}, {4, 7}, {2, 5}, {5, 8}},
1850 };
1851
1852 float cross[2][3] = {{0.0f}};
1853
1854 for (int i = 0; i < 6; i++) {
1855 for (int axis = 0; axis < 2; axis++) {
1856 if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
1857 float delta[3];
1858 sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
1859 add_v3_v3(cross[axis], delta);
1860 }
1861 }
1862 }
1863
1864 cross_v3_v3v3(r_normal, cross[0], cross[1]);
1865
1866 if (normalize_v3(r_normal) != 0.0f) {
1867 return true;
1868 }
1869 return false;
1870}
1871
1873 const int mval[2],
1874 const double depth,
1875 float r_location_world[3])
1876{
1877 float centx = float(mval[0]) + 0.5f;
1878 float centy = float(mval[1]) + 0.5f;
1879 return ED_view3d_unproject_v3(region, centx, centy, depth, r_location_world);
1880}
1881
Functions to insert, delete or modify keyframes.
Functionality to interact with keying sets.
Camera data-block and utility functions.
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y)
bool BKE_camera_view_frame_fit_to_scene(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *camera_ob, float r_co[3], float *r_scale, float *r_clip_start, float *r_clip_end)
#define CAMERA_PARAM_ZOOM_INIT_PERSP
Definition BKE_camera.h:76
void BKE_camera_params_init(CameraParams *params)
void BKE_camera_params_from_view3d(CameraParams *params, const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d)
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob)
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy)
#define CAMERA_PARAM_ZOOM_INIT_CAMOB
Definition BKE_camera.h:75
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
General operations, lookup, etc. for blender objects.
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
void BKE_object_tfm_protected_backup(const Object *ob, ObjectTfmProtectedChannels *obtfm)
void BKE_object_apply_mat4_ex(Object *ob, const float mat[4][4], Object *parent, const float parentinv[4][4], bool use_compat)
void BKE_object_tfm_protected_restore(Object *ob, const ObjectTfmProtectedChannels *obtfm, short protectflag)
bool BKE_scene_uses_blender_workbench(const Scene *scene)
Definition scene.cc:2829
float BKE_screen_view3d_zoom_from_fac(float zoomfac)
Definition screen.cc:1044
ARegion * BKE_area_find_region_active_win(const ScrArea *area)
Definition screen.cc:859
ScrArea * BKE_screen_find_big_area(const bScreen *screen, int spacetype, short min)
Definition screen.cc:944
float BKE_screen_view3d_zoom_to_fac(float camzoom)
Definition screen.cc:1039
Generic array manipulation API.
#define BLI_array_iter_spiral_square(arr, arr_shape, center, test_fn, user_data)
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2], const int p2[2], bool(*callback)(int, int, void *), void *user_data)
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE float srgb_to_grayscale(const float rgb[3])
#define M_SQRT1_2
#define M_PI_4
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
bool isect_planes_v3_fn(const float planes[][4], int planes_len, float eps_coplanar, float eps_isect, void(*callback_fn)(const float co[3], int i, int j, int k, void *user_data), void *user_data)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) ATTR_NONNULL()
void normalize_m3(float R[3][3]) ATTR_NONNULL()
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool is_negative_m4(const float mat[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_m4_v4(const float mat[4][4], float r[4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void invert_qt_normalized(float q[4])
void quat_to_mat4(float m[4][4], const float q[4])
void mul_qt_v3(const float q[4], float r[3])
void invert_qt_qt_normalized(float q1[4], const float q2[4])
float focallength_to_fov(float focal_length, float sensor)
void copy_qt_qt(float q[4], const float a[4])
void mat3_normalized_to_quat(float q[4], const float mat[3][3])
float angle_signed_qtqt(const float q1[4], const float q2[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void clamp_v3(float vec[3], float min, float max)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v4_v4(float r[4], const float a[4])
MINLINE void negate_v3(float r[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size)
Definition rct.cc:466
#define CLAMP(a, b, c)
#define INIT_MINMAX(min, max)
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_PARAMETERS
Definition DNA_ID.h:1138
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ ID_OB
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ ROT_MODE_EUL
@ CAM_ORTHO
#define DEFAULT_SENSOR_WIDTH
@ OB_SOLID
@ OB_RENDER
@ OB_MODE_TEXTURE_PAINT
Object is a sort of wrapper for general info.
@ OB_CAMERA
@ OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK
@ OB_LOCK_ROT4D
@ OB_LOCK_SCALEZ
@ OB_LOCK_SCALEX
@ OB_LOCK_SCALEY
@ OB_LOCK_SCALE
@ RGN_ALIGN_QSPLIT
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ USER_AUTOPERSP
@ V3D_SHADING_BACKGROUND_VIEWPORT
@ V3D_SHADING_BACKGROUND_WORLD
@ V3D_SHADING_TEXTURE_COLOR
@ V3D_LOCK_CAMERA
#define RV3D_VIEW_IS_AXIS(view)
@ RV3D_VIEW_AXIS_ROLL_270
@ RV3D_VIEW_AXIS_ROLL_0
@ RV3D_VIEW_FRONT
@ RV3D_VIEW_BOTTOM
@ RV3D_VIEW_LEFT
@ RV3D_VIEW_RIGHT
@ RV3D_VIEW_TOP
@ RV3D_VIEW_BACK
@ RV3D_VIEW_USER
#define RV3D_CAMZOOM_MAX
#define RV3D_CAMZOOM_MIN_FACTOR
#define RV3D_LOCK_FLAGS(rv3d)
#define RV3D_CAMZOOM_MAX_FACTOR
@ RV3D_ZOFFSET_DISABLED
@ RV3D_CLIPPING
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
#define RV3D_CAMZOOM_MIN
@ RV3D_LOCK_ANY_TRANSFORM
@ RV3D_LOCK_ROTATION
@ RV3D_BOXVIEW
@ RV3D_BOXCLIP
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
bool ED_undo_is_memfile_compatible(const bContext *C)
Definition ed_undo.cc:387
void ED_undo_grouped_push(bContext *C, const char *str)
Definition ed_undo.cc:337
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])
#define VIEW3D_DIST_FALLBACK
bool ED_view3d_unproject_v3(const ARegion *region, float regionx, float regiony, float regionz, float world[3])
static AppView * view
#define GPU_matrix_set(x)
#define GPU_matrix_projection_set(x)
void GPU_polygon_offset(float viewdist, float dist)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_BACK
@ TH_TEXT_HI
@ WM_EVENT_IS_CONSECUTIVE
Definition WM_types.hh:692
#define NC_ANIMATION
Definition WM_types.hh:388
#define NA_ADDED
Definition WM_types.hh:586
#define ND_TRANSFORM
Definition WM_types.hh:456
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define ND_KEYFRAME
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:379
#define NC_SPACE
Definition WM_types.hh:392
#define U
BMesh const char void * data
BPy_StructRNA * depsgraph
void append(const T &value)
nullptr float
#define str(s)
#define GS(x)
uint pos
#define printf(...)
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
void autokeyframe_object(bContext *C, const Scene *scene, Object *ob, Span< RNAPath > rna_paths)
#define fabsf
#define atanf
#define tanf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
void * regiondata
struct ARegion * prev
float vec[8][3]
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
void * last
short transflag
float parentinv[4][4]
short protectflag
struct Object * parent
float viewcamtexcofac[4]
float persmat[4][4]
float clip[6][4]
float viewmat[4][4]
float persmatob[4][4]
float viewinv[4][4]
struct BoundBox * clipbb
float winmat[4][4]
View3DShading shading
struct SceneDisplay display
struct World * world
ListBase regionbase
float background_color[3]
struct Object * camera
char ob_center_bone[64]
short ob_center_cursor
struct Object * ob_center
View3DShading shading
float clip_start
unsigned short w
Definition ED_view3d.hh:86
float * depths
Definition ED_view3d.hh:89
double depth_range[2]
Definition ED_view3d.hh:90
unsigned short h
Definition ED_view3d.hh:86
float horr
int ymin
int ymax
int xmin
int xmax
eWM_EventFlag flag
Definition WM_types.hh:788
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
void view3d_depths_rect_create(ARegion *region, rcti *rect, ViewDepths *r_d)
float view3d_depth_near(ViewDepths *d)
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
bool ED_view3d_camera_autokey(const Scene *scene, ID *id_key, bContext *C, const bool do_rotate, const bool do_translate)
static bool view3d_camera_to_view_selected_impl(Main *bmain, Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, float *r_clip_start, float *r_clip_end)
bool ED_view3d_depth_read_cached(const ViewDepths *vd, const int mval[2], int margin, float *r_depth)
bool ED_view3d_camera_to_view_selected_with_set_clipping(Main *bmain, Depsgraph *depsgraph, const Scene *scene, Object *camera_ob)
bool ED_view3d_depth_unproject_v3(const ARegion *region, const int mval[2], const double depth, float r_location_world[3])
static bool view3d_camera_lock_undo_ex(const char *str, const View3D *v3d, const RegionView3D *rv3d, bContext *C, const bool undo_group)
static bool depth_read_test_fn(const void *value, void *userdata)
char ED_view3d_axis_view_opposite(char view)
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
bool ED_view3d_depth_read_cached_seg(const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *r_depth)
void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *region, const Object *ob, const rcti *rect)
void ED_view3d_autodist_last_clear(wmWindow *win)
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)
static bool view3d_boundbox_clip_m4(const BoundBox *bb, const float persmatob[4][4])
bool ED_view3d_lock(RegionView3D *rv3d)
char ED_view3d_lock_view_from_index(int index)
void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
void ED_view3d_lastview_store(RegionView3D *rv3d)
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_distance_set_from_location(RegionView3D *rv3d, const float dist_co[3], const float dist_min)
bool ED_view3d_camera_view_zoom_scale(RegionView3D *rv3d, const float scale)
bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4])
bool ED_view3d_autodist(ARegion *region, View3D *v3d, const int mval[2], float mouse_worldloc[3], const float fallback_depth_pt[3])
float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
blender::Bounds< float > ED_view3d_dist_soft_range_get(const View3D *v3d, const bool use_persp_range)
void ED_view3d_to_object(const Depsgraph *depsgraph, Object *ob, const float ofs[3], const float quat[4], const float dist)
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
float ED_view3d_dist_soft_min_get(const View3D *v3d, const bool use_persp_range)
bool ED_view3d_autodist_last_get(wmWindow *win, float r_ofs[3])
static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
void view3d_region_operator_needs_gpu(ARegion *region)
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
float ED_view3d_offset_distance(const float mat[4][4], const float ofs[3], const float fallback_dist)
bool ED_view3d_camera_lock_autokey(View3D *v3d, RegionView3D *rv3d, bContext *C, const bool do_rotate, const bool do_translate)
static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin)
bool ED_view3d_depth_read_cached_normal(const ARegion *region, const ViewDepths *depths, const int mval[2], float r_normal[3])
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
bool ED_view3d_context_activate(bContext *C)
void ED_view3d_lock_clear(View3D *v3d)
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)
void view3d_boxview_copy(ScrArea *area, ARegion *region)
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
bool ED_view3d_autodist_simple(ARegion *region, const int mval[2], float mouse_worldloc[3], int margin, const float *force_depth)
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const char persp)
bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
bool ED_view3d_viewplane_get(const Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, rctf *r_viewplane, float *r_clip_start, float *r_clip_end, float *r_pixsize)
void view3d_boxview_sync(ScrArea *area, ARegion *region)
bool ED_view3d_camera_to_view_selected(Main *bmain, Depsgraph *depsgraph, const Scene *scene, Object *camera_ob)
static void points_in_planes_minmax_fn(const float co[3], int, int, int, void *user_data_p)
bool ED_view3d_clip_range_get(const Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d, const bool use_ortho_factor, float *r_clip_start, float *r_clip_end)
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
void ED_view3d_text_colors_get(const Scene *scene, const View3D *v3d, float r_text_color[4], float r_shadow_color[4])
static void view3d_boxview_clip(ScrArea *area)
void view3d_operator_needs_gpu(const bContext *C)
void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
Camera * ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
float ED_view3d_radius_to_dist(const View3D *v3d, const ARegion *region, const Depsgraph *depsgraph, const char persp, const bool use_aspect, const float radius)
bool ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon, char *r_view, char *r_view_axis_roll)
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
bool ED_view3d_camera_lock_undo_test(const View3D *v3d, const RegionView3D *rv3d, bContext *C)
static float view3d_quat_axis[6][4][4]
static const char * view3d_autodepth_last_id
bool ED_view3d_quat_to_axis_view_and_reset_quat(float quat[4], const float epsilon, char *r_view, char *r_view_axis_roll)
static bool depth_segment_cb(int x, int y, void *user_data)
bool ED_view3d_has_workbench_in_texture_color(const Scene *scene, const Object *ob, const View3D *v3d)
bool ED_view3d_camera_lock_undo_grouped_push(const char *str, const View3D *v3d, const RegionView3D *rv3d, bContext *C)
bool WM_event_consecutive_gesture_test(const wmEvent *event)
void * WM_event_consecutive_data_get(wmWindow *win, const char *id)
void WM_event_consecutive_data_free(wmWindow *win)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_consecutive_data_set(wmWindow *win, const char *id, void *custom_data)
void wmViewport(const rcti *winrct)
uint8_t flag
Definition wm_window.cc:145