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