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