Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / view3d_utils.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/editors/space_view3d/view3d_utils.c
25  *  \ingroup spview3d
26  *
27  * 3D View checks and manipulation (no operators).
28  */
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "DNA_camera_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_world_types.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_bitmap_draw_2d.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_camera.h"
49 #include "BKE_context.h"
50 #include "BKE_main.h"
51 #include "BKE_object.h"
52 #include "BKE_screen.h"
53
54 #include "DEG_depsgraph.h"
55 #include "DEG_depsgraph_query.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60 #include "GPU_matrix.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_keyframing.h"
66 #include "ED_screen.h"
67 #include "ED_view3d.h"
68
69 #include "UI_resources.h"
70
71 #include "view3d_intern.h"  /* own include */
72
73 /* -------------------------------------------------------------------- */
74 /** \name View Data Access Utilities
75  *
76  * \{ */
77
78 void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
79 {
80         switch (v3d->shading.background_type) {
81                 case V3D_SHADING_BACKGROUND_WORLD:
82                         copy_v3_v3(r_color, &scene->world->horr);
83                         break;
84                 case V3D_SHADING_BACKGROUND_VIEWPORT:
85                         copy_v3_v3(r_color, v3d->shading.background_color);
86                         break;
87                 case V3D_SHADING_BACKGROUND_THEME:
88                 default:
89                         UI_GetThemeColor3fv(TH_HIGH_GRAD, r_color);
90                         break;
91         }
92 }
93
94 void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3])
95 {
96         const View3DCursor *cursor = &scene->cursor;
97         quat_to_mat3(mat, cursor->rotation);
98 }
99
100 void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4])
101 {
102         const View3DCursor *cursor = &scene->cursor;
103         quat_to_mat4(mat, cursor->rotation);
104         copy_v3_v3(mat[3], cursor->location);
105 }
106
107 Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
108 {
109         /* establish the camera object, so we can default to view mapping if anything is wrong with it */
110         if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
111                 return v3d->camera->data;
112         }
113         else {
114                 return NULL;
115         }
116 }
117
118 void ED_view3d_dist_range_get(
119         const View3D *v3d,
120         float r_dist_range[2])
121 {
122         r_dist_range[0] = v3d->grid * 0.001f;
123         r_dist_range[1] = v3d->far * 10.0f;
124 }
125
126 /**
127  * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
128  */
129 bool ED_view3d_clip_range_get(
130         Depsgraph *depsgraph,
131         const View3D *v3d, const RegionView3D *rv3d,
132         float *r_clipsta, float *r_clipend,
133         const bool use_ortho_factor)
134 {
135         CameraParams params;
136
137         BKE_camera_params_init(&params);
138         BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
139
140         if (use_ortho_factor && params.is_ortho) {
141                 const float fac = 2.0f / (params.clipend - params.clipsta);
142                 params.clipsta *= fac;
143                 params.clipend *= fac;
144         }
145
146         if (r_clipsta) *r_clipsta = params.clipsta;
147         if (r_clipend) *r_clipend = params.clipend;
148
149         return params.is_ortho;
150 }
151
152 bool ED_view3d_viewplane_get(
153         Depsgraph *depsgraph,
154         const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
155         rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
156 {
157         CameraParams params;
158
159         BKE_camera_params_init(&params);
160         BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
161         BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
162
163         if (r_viewplane) *r_viewplane = params.viewplane;
164         if (r_clipsta) *r_clipsta = params.clipsta;
165         if (r_clipend) *r_clipend = params.clipend;
166         if (r_pixsize) *r_pixsize = params.viewdx;
167
168         return params.is_ortho;
169 }
170
171 /** \} */
172
173
174 /* -------------------------------------------------------------------- */
175 /** \name View State/Context Utilities
176  *
177  * \{ */
178
179 /**
180  * Use this call when executing an operator,
181  * event system doesn't set for each event the OpenGL drawing context.
182  */
183 void view3d_operator_needs_opengl(const bContext *C)
184 {
185         wmWindow *win = CTX_wm_window(C);
186         ARegion *ar = CTX_wm_region(C);
187
188         view3d_region_operator_needs_opengl(win, ar);
189 }
190
191 void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *ar)
192 {
193         /* for debugging purpose, context should always be OK */
194         if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) {
195                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
196         }
197         else {
198                 RegionView3D *rv3d = ar->regiondata;
199
200                 wmViewport(&ar->winrct); // TODO: bad
201                 GPU_matrix_projection_set(rv3d->winmat);
202                 GPU_matrix_set(rv3d->viewmat);
203         }
204 }
205
206 /**
207  * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727]
208  */
209 void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
210 {
211         float viewdist;
212
213         if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
214                 return;
215         }
216
217         viewdist = rv3d->dist;
218
219         /* special exception for ortho camera (viewdist isnt used for perspective cameras) */
220         if (dist != 0.0f) {
221                 if (rv3d->persp == RV3D_CAMOB) {
222                         if (rv3d->is_persp == false) {
223                                 viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
224                         }
225                 }
226         }
227
228         bglPolygonOffset(viewdist, dist);
229 }
230
231 bool ED_view3d_context_activate(bContext *C)
232 {
233         bScreen *sc = CTX_wm_screen(C);
234         ScrArea *sa = CTX_wm_area(C);
235         ARegion *ar;
236
237         /* sa can be NULL when called from python */
238         if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
239                 sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
240         }
241
242         if (sa == NULL) {
243                 return false;
244         }
245
246         ar = BKE_area_find_region_active_win(sa);
247         if (ar == NULL) {
248                 return false;
249         }
250
251         /* bad context switch .. */
252         CTX_wm_area_set(C, sa);
253         CTX_wm_region_set(C, ar);
254
255         return true;
256 }
257
258 /** \} */
259
260 /* -------------------------------------------------------------------- */
261 /** \name View Clipping Utilities
262  *
263  * \{ */
264
265 void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
266 {
267         int val;
268
269         for (val = 0; val < 4; val++) {
270                 normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
271                 if (UNLIKELY(is_flip)) {
272                         negate_v3(clip[val]);
273                 }
274
275                 clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
276         }
277 }
278
279 void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect)
280 {
281         /* init in case unproject fails */
282         memset(bb->vec, 0, sizeof(bb->vec));
283
284         /* four clipping planes and bounding volume */
285         /* first do the bounding volume */
286         for (int val = 0; val < 4; val++) {
287                 float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
288                 float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
289
290                 ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]);
291                 ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]);
292         }
293
294         /* optionally transform to object space */
295         if (ob) {
296                 float imat[4][4];
297                 invert_m4_m4(imat, ob->obmat);
298
299                 for (int val = 0; val < 8; val++) {
300                         mul_m4_v3(imat, bb->vec[val]);
301                 }
302         }
303
304         /* verify if we have negative scale. doing the transform before cross
305          * product flips the sign of the vector compared to doing cross product
306          * before transform then, so we correct for that. */
307         int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false;
308
309         ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
310 }
311
312 /** \} */
313
314 /* -------------------------------------------------------------------- */
315 /** \name View Bound-Box Utilities
316  *
317  * \{ */
318
319 static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
320 {
321         int a, flag = -1, fl;
322
323         for (a = 0; a < 8; a++) {
324                 float vec[4], min, max;
325                 copy_v3_v3(vec, bb->vec[a]);
326                 vec[3] = 1.0;
327                 mul_m4_v4(persmatob, vec);
328                 max = vec[3];
329                 min = -vec[3];
330
331                 fl = 0;
332                 if (vec[0] < min) fl += 1;
333                 if (vec[0] > max) fl += 2;
334                 if (vec[1] < min) fl += 4;
335                 if (vec[1] > max) fl += 8;
336                 if (vec[2] < min) fl += 16;
337                 if (vec[2] > max) fl += 32;
338
339                 flag &= fl;
340                 if (flag == 0) return true;
341         }
342
343         return false;
344 }
345
346 bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
347 {
348         /* return 1: draw */
349
350         float persmatob[4][4];
351
352         if (bb == NULL) return true;
353         if (bb->flag & BOUNDBOX_DISABLED) return true;
354
355         mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
356
357         return view3d_boundbox_clip_m4(bb, persmatob);
358 }
359
360 bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
361 {
362         if (bb == NULL) return true;
363         if (bb->flag & BOUNDBOX_DISABLED) return true;
364
365         return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
366 }
367
368 /** \} */
369
370 /* -------------------------------------------------------------------- */
371 /** \name View Perspective & Mode Switching
372  *
373  * Misc view utility functions.
374  * \{ */
375
376 bool ED_view3d_offset_lock_check(const  View3D *v3d, const  RegionView3D *rv3d)
377 {
378         return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
379 }
380
381 /**
382  * Use to store the last view, before entering camera view.
383  */
384 void ED_view3d_lastview_store(RegionView3D *rv3d)
385 {
386         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
387         rv3d->lview = rv3d->view;
388         if (rv3d->persp != RV3D_CAMOB) {
389                 rv3d->lpersp = rv3d->persp;
390         }
391 }
392
393 void ED_view3d_lock_clear(View3D *v3d)
394 {
395         v3d->ob_centre = NULL;
396         v3d->ob_centre_bone[0] = '\0';
397         v3d->ob_centre_cursor = false;
398         v3d->flag2 &= ~V3D_LOCK_CAMERA;
399 }
400
401 /**
402  * For viewport operators that exit camera perspective.
403  *
404  * \note This differs from simply setting ``rv3d->persp = persp`` because it
405  * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
406  * otherwise switching out of camera view may jump to a different part of the scene.
407  */
408 void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const char persp)
409 {
410         BLI_assert(rv3d->persp == RV3D_CAMOB);
411         BLI_assert(persp != RV3D_CAMOB);
412
413         if (v3d->camera) {
414                 Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
415                 rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
416                 ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
417         }
418
419         if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
420                 rv3d->persp = persp;
421         }
422 }
423 /**
424  * Action to take when rotating the view,
425  * handle auto-persp and logic for switching out of views.
426  *
427  * shared with NDOF.
428  */
429 bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *ar)
430 {
431         RegionView3D *rv3d = ar->regiondata;
432         const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
433
434         BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
435
436         if (ED_view3d_camera_lock_check(v3d, rv3d))
437                 return false;
438
439         if (rv3d->persp != RV3D_PERSP) {
440                 if (rv3d->persp == RV3D_CAMOB) {
441                         /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
442                         char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
443                         ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, persp);
444                 }
445                 else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
446                         rv3d->persp = RV3D_PERSP;
447                 }
448                 return true;
449         }
450
451         return false;
452 }
453
454 /** \} */
455
456 /* -------------------------------------------------------------------- */
457 /** \name Camera Lock API
458  *
459  * Lock the camera to the view-port, allowing view manipulation to transform the camera.
460  * \{ */
461
462 /**
463  * \return true when the view-port is locked to its camera.
464  */
465 bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
466 {
467         return ((v3d->camera) &&
468                 (!ID_IS_LINKED(v3d->camera)) &&
469                 (v3d->flag2 & V3D_LOCK_CAMERA) &&
470                 (rv3d->persp == RV3D_CAMOB));
471 }
472
473 /**
474  * Apply the camera object transformation to the view-port.
475  * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
476  */
477 void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
478 {
479         if (ED_view3d_camera_lock_check(v3d, rv3d)) {
480                 Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
481                 if (calc_dist) {
482                         /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
483                         rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
484                 }
485                 ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
486         }
487 }
488
489 void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
490 {
491         ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
492 }
493
494 /**
495  * Apply the view-port transformation back to the camera object.
496  *
497  * \return true if the camera is moved.
498  */
499 bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
500 {
501         if (ED_view3d_camera_lock_check(v3d, rv3d)) {
502                 ObjectTfmProtectedChannels obtfm;
503                 Object *root_parent;
504
505                 if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
506                         Object *ob_update;
507                         float tmat[4][4];
508                         float imat[4][4];
509                         float view_mat[4][4];
510                         float diff_mat[4][4];
511                         float parent_mat[4][4];
512
513                         while (root_parent->parent) {
514                                 root_parent = root_parent->parent;
515                         }
516                         Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
517                         Object *root_parent_eval = DEG_get_evaluated_object(depsgraph, root_parent);
518
519                         ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
520
521                         normalize_m4_m4(tmat, ob_camera_eval->obmat);
522
523                         invert_m4_m4(imat, tmat);
524                         mul_m4_m4m4(diff_mat, view_mat, imat);
525
526                         mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->obmat);
527
528                         BKE_object_tfm_protected_backup(root_parent, &obtfm);
529                         BKE_object_apply_mat4(root_parent, parent_mat, true, false);
530                         BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
531
532                         ob_update = v3d->camera;
533                         while (ob_update) {
534                                 DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
535                                 WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
536                                 ob_update = ob_update->parent;
537                         }
538                 }
539                 else {
540                         /* always maintain the same scale */
541                         const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
542                         BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
543                         ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
544                         BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
545
546                         DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
547                         WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
548                 }
549
550                 return true;
551         }
552         else {
553                 return false;
554         }
555 }
556
557 bool ED_view3d_camera_autokey(
558         Scene *scene, ID *id_key,
559         struct bContext *C, const bool do_rotate, const bool do_translate)
560 {
561         if (autokeyframe_cfra_can_key(scene, id_key)) {
562                 const float cfra = (float)CFRA;
563                 ListBase dsources = {NULL, NULL};
564
565                 /* add data-source override for the camera object */
566                 ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
567
568                 /* insert keyframes
569                  * 1) on the first frame
570                  * 2) on each subsequent frame
571                  *    TODO: need to check in future that frame changed before doing this
572                  */
573                 if (do_rotate) {
574                         struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
575                         ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
576                 }
577                 if (do_translate) {
578                         struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
579                         ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
580                 }
581
582                 /* free temp data */
583                 BLI_freelistN(&dsources);
584
585                 return true;
586         }
587         else {
588                 return false;
589         }
590 }
591
592 /**
593  * Call after modifying a locked view.
594  *
595  * \note Not every view edit currently auto-keys (numpad for eg),
596  * this is complicated because of smoothview.
597  */
598 bool ED_view3d_camera_lock_autokey(
599         View3D *v3d, RegionView3D *rv3d,
600         struct bContext *C, const bool do_rotate, const bool do_translate)
601 {
602         /* similar to ED_view3d_cameracontrol_update */
603         if (ED_view3d_camera_lock_check(v3d, rv3d)) {
604                 Scene *scene = CTX_data_scene(C);
605                 ID *id_key;
606                 Object *root_parent;
607                 if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
608                         while (root_parent->parent) {
609                                 root_parent = root_parent->parent;
610                         }
611                         id_key = &root_parent->id;
612                 }
613                 else {
614                         id_key = &v3d->camera->id;
615                 }
616
617                 return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
618         }
619         else {
620                 return false;
621         }
622 }
623
624 /** \} */
625
626
627
628 /* -------------------------------------------------------------------- */
629 /** \name Box View Support
630  *
631  * Use with quad-split so each view is clipped by the bounds of each view axis.
632  * \{ */
633
634 static void view3d_boxview_clip(ScrArea *sa)
635 {
636         ARegion *ar;
637         BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
638         float clip[6][4];
639         float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
640         int val;
641
642         /* create bounding box */
643         for (ar = sa->regionbase.first; ar; ar = ar->next) {
644                 if (ar->regiontype == RGN_TYPE_WINDOW) {
645                         RegionView3D *rv3d = ar->regiondata;
646
647                         if (rv3d->viewlock & RV3D_BOXCLIP) {
648                                 if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
649                                         if (ar->winx > ar->winy) x1 = rv3d->dist;
650                                         else x1 = ar->winx * rv3d->dist / ar->winy;
651
652                                         if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx;
653                                         else y1 = rv3d->dist;
654                                         copy_v2_v2(ofs, rv3d->ofs);
655                                 }
656                                 else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
657                                         ofs[2] = rv3d->ofs[2];
658
659                                         if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx;
660                                         else z1 = rv3d->dist;
661                                 }
662                         }
663                 }
664         }
665
666         for (val = 0; val < 8; val++) {
667                 if (ELEM(val, 0, 3, 4, 7))
668                         bb->vec[val][0] = -x1 - ofs[0];
669                 else
670                         bb->vec[val][0] =  x1 - ofs[0];
671
672                 if (ELEM(val, 0, 1, 4, 5))
673                         bb->vec[val][1] = -y1 - ofs[1];
674                 else
675                         bb->vec[val][1] =  y1 - ofs[1];
676
677                 if (val > 3)
678                         bb->vec[val][2] = -z1 - ofs[2];
679                 else
680                         bb->vec[val][2] =  z1 - ofs[2];
681         }
682
683         /* normals for plane equations */
684         normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
685         normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
686         normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
687         normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
688         normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
689         normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
690
691         /* then plane equations */
692         for (val = 0; val < 6; val++) {
693                 clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
694         }
695
696         /* create bounding box */
697         for (ar = sa->regionbase.first; ar; ar = ar->next) {
698                 if (ar->regiontype == RGN_TYPE_WINDOW) {
699                         RegionView3D *rv3d = ar->regiondata;
700
701                         if (rv3d->viewlock & RV3D_BOXCLIP) {
702                                 rv3d->rflag |= RV3D_CLIPPING;
703                                 memcpy(rv3d->clip, clip, sizeof(clip));
704                                 if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
705                                 rv3d->clipbb = MEM_dupallocN(bb);
706                         }
707                 }
708         }
709         MEM_freeN(bb);
710 }
711
712 /**
713  * Find which axis values are shared between both views and copy to \a rv3d_dst
714  * taking axis flipping into account.
715  */
716 static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
717 {
718         /* absolute axis values above this are considered to be set (will be ~1.0f) */
719         const float axis_eps = 0.5f;
720         float viewinv[4];
721
722         /* use the view rotation to identify which axis to sync on */
723         float view_axis_all[4][3] = {
724             {1.0f, 0.0f, 0.0f},
725             {0.0f, 1.0f, 0.0f},
726             {1.0f, 0.0f, 0.0f},
727             {0.0f, 1.0f, 0.0f}};
728
729         float *view_src_x = &view_axis_all[0][0];
730         float *view_src_y = &view_axis_all[1][0];
731
732         float *view_dst_x = &view_axis_all[2][0];
733         float *view_dst_y = &view_axis_all[3][0];
734         int i;
735
736
737         /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
738         if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
739                 return;
740         }
741         invert_qt_normalized(viewinv);
742         mul_qt_v3(viewinv, view_src_x);
743         mul_qt_v3(viewinv, view_src_y);
744
745         if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
746                 return;
747         }
748         invert_qt_normalized(viewinv);
749         mul_qt_v3(viewinv, view_dst_x);
750         mul_qt_v3(viewinv, view_dst_y);
751
752         /* check source and dest have a matching axis */
753         for (i = 0; i < 3; i++) {
754                 if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
755                     ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
756                 {
757                         rv3d_dst->ofs[i] = rv3d_src->ofs[i];
758                 }
759         }
760 }
761
762 /* sync center/zoom view of region to others, for view transforms */
763 void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
764 {
765         ARegion *artest;
766         RegionView3D *rv3d = ar->regiondata;
767         short clip = 0;
768
769         for (artest = sa->regionbase.first; artest; artest = artest->next) {
770                 if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
771                         RegionView3D *rv3dtest = artest->regiondata;
772
773                         if (rv3dtest->viewlock & RV3D_LOCKED) {
774                                 rv3dtest->dist = rv3d->dist;
775                                 view3d_boxview_sync_axis(rv3dtest, rv3d);
776                                 clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
777
778                                 ED_region_tag_redraw(artest);
779                         }
780                 }
781         }
782
783         if (clip) {
784                 view3d_boxview_clip(sa);
785         }
786 }
787
788 /* for home, center etc */
789 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
790 {
791         ARegion *artest;
792         RegionView3D *rv3d = ar->regiondata;
793         bool clip = false;
794
795         for (artest = sa->regionbase.first; artest; artest = artest->next) {
796                 if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
797                         RegionView3D *rv3dtest = artest->regiondata;
798
799                         if (rv3dtest->viewlock) {
800                                 rv3dtest->dist = rv3d->dist;
801                                 copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
802                                 ED_region_tag_redraw(artest);
803
804                                 clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
805                         }
806                 }
807         }
808
809         if (clip) {
810                 view3d_boxview_clip(sa);
811         }
812 }
813
814 /* 'clip' is used to know if our clip setting has changed */
815 void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
816 {
817         ARegion *ar_sync = NULL;
818         RegionView3D *rv3d = ar->regiondata;
819         short viewlock;
820         /* this function copies flags from the first of the 3 other quadview
821          * regions to the 2 other, so it assumes this is the region whose
822          * properties are always being edited, weak */
823         viewlock = rv3d->viewlock;
824
825         if ((viewlock & RV3D_LOCKED) == 0) {
826                 do_clip = (viewlock & RV3D_BOXCLIP) != 0;
827                 viewlock = 0;
828         }
829         else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
830                 do_clip = true;
831                 viewlock &= ~RV3D_BOXCLIP;
832         }
833
834         for (; ar; ar = ar->prev) {
835                 if (ar->alignment == RGN_ALIGN_QSPLIT) {
836                         rv3d = ar->regiondata;
837                         rv3d->viewlock = viewlock;
838
839                         if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
840                                 rv3d->rflag &= ~RV3D_BOXCLIP;
841                         }
842
843                         /* use ar_sync so we sync with one of the aligned views below
844                          * else the view jumps on changing view settings like 'clip'
845                          * since it copies from the perspective view */
846                         ar_sync = ar;
847                 }
848         }
849
850         if (rv3d->viewlock & RV3D_BOXVIEW) {
851                 view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
852         }
853
854         /* ensure locked regions have an axis, locked user views don't make much sense */
855         if (viewlock & RV3D_LOCKED) {
856                 int index_qsplit = 0;
857                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
858                         if (ar->alignment == RGN_ALIGN_QSPLIT) {
859                                 rv3d = ar->regiondata;
860                                 if (rv3d->viewlock) {
861                                         if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
862                                                 rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
863                                                 rv3d->persp = RV3D_ORTHO;
864                                                 ED_view3d_lock(rv3d);
865                                         }
866                                 }
867                                 index_qsplit++;
868                         }
869                 }
870         }
871
872         ED_area_tag_redraw(sa);
873 }
874
875 /** \} */
876
877 /* -------------------------------------------------------------------- */
878 /** \name View Auto-Depth Utilities
879  * \{ */
880
881 static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin)
882 {
883         ViewDepths depth_temp = {0};
884         rcti rect;
885         float depth_close;
886
887         if (margin == 0) {
888                 /* Get Z Depths, needed for perspective, nice for ortho */
889                 rect.xmin = mval[0];
890                 rect.ymin = mval[1];
891                 rect.xmax = mval[0] + 1;
892                 rect.ymax = mval[1] + 1;
893         }
894         else {
895                 BLI_rcti_init_pt_radius(&rect, mval, margin);
896         }
897
898         view3d_update_depths_rect(ar, &depth_temp, &rect);
899         depth_close = view3d_depth_near(&depth_temp);
900         MEM_SAFE_FREE(depth_temp.depths);
901         return depth_close;
902 }
903
904 /**
905  * Get the world-space 3d location from a screen-space 2d point.
906  *
907  * \param mval: Input screen-space pixel location.
908  * \param mouse_worldloc: Output world-space location.
909  * \param fallback_depth_pt: Use this points depth when no depth can be found.
910  */
911 bool ED_view3d_autodist(
912         Depsgraph *depsgraph, ARegion *ar, View3D *v3d,
913         const int mval[2], float mouse_worldloc[3],
914         const bool alphaoverride, const float fallback_depth_pt[3])
915 {
916         float depth_close;
917         int margin_arr[] = {0, 2, 4};
918         int i;
919         bool depth_ok = false;
920
921         /* Get Z Depths, needed for perspective, nice for ortho */
922         ED_view3d_draw_depth(depsgraph, ar, v3d, alphaoverride);
923
924         /* Attempt with low margin's first */
925         i = 0;
926         do {
927                 depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
928                 depth_ok = (depth_close != FLT_MAX);
929         } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
930
931         if (depth_ok) {
932                 float centx = (float)mval[0] + 0.5f;
933                 float centy = (float)mval[1] + 0.5f;
934
935                 if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) {
936                         return true;
937                 }
938         }
939
940         if (fallback_depth_pt) {
941                 ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
942                 return true;
943         }
944         else {
945                 return false;
946         }
947 }
948
949 void ED_view3d_autodist_init(Depsgraph *depsgraph,
950         ARegion *ar, View3D *v3d, int mode)
951 {
952         /* Get Z Depths, needed for perspective, nice for ortho */
953         switch (mode) {
954                 case 0:
955                         ED_view3d_draw_depth(depsgraph, ar, v3d, true);
956                         break;
957                 case 1:
958                 {
959                         Scene *scene = DEG_get_evaluated_scene(depsgraph);
960                         ED_view3d_draw_depth_gpencil(depsgraph, scene, ar, v3d);
961                         break;
962                 }
963         }
964 }
965
966 /* no 4x4 sampling, run #ED_view3d_autodist_init first */
967 bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
968                                int margin, float *force_depth)
969 {
970         float depth;
971
972         /* Get Z Depths, needed for perspective, nice for ortho */
973         if (force_depth)
974                 depth = *force_depth;
975         else
976                 depth = view_autodist_depth_margin(ar, mval, margin);
977
978         if (depth == FLT_MAX)
979                 return false;
980
981         float centx = (float)mval[0] + 0.5f;
982         float centy = (float)mval[1] + 0.5f;
983         return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc);
984 }
985
986 bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
987 {
988         *depth = view_autodist_depth_margin(ar, mval, margin);
989
990         return (*depth != FLT_MAX);
991 }
992
993 static bool depth_segment_cb(int x, int y, void *userData)
994 {
995         struct { ARegion *ar; int margin; float depth; } *data = userData;
996         int mval[2];
997         float depth;
998
999         mval[0] = x;
1000         mval[1] = y;
1001
1002         depth = view_autodist_depth_margin(data->ar, mval, data->margin);
1003
1004         if (depth != FLT_MAX) {
1005                 data->depth = depth;
1006                 return 0;
1007         }
1008         else {
1009                 return 1;
1010         }
1011 }
1012
1013 bool ED_view3d_autodist_depth_seg(
1014         ARegion *ar, const int mval_sta[2], const int mval_end[2],
1015         int margin, float *depth)
1016 {
1017         struct { ARegion *ar; int margin; float depth; } data = {NULL};
1018         int p1[2];
1019         int p2[2];
1020
1021         data.ar = ar;
1022         data.margin = margin;
1023         data.depth = FLT_MAX;
1024
1025         copy_v2_v2_int(p1, mval_sta);
1026         copy_v2_v2_int(p2, mval_end);
1027
1028         BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
1029
1030         *depth = data.depth;
1031
1032         return (*depth != FLT_MAX);
1033 }
1034
1035 /** \} */
1036
1037 /* -------------------------------------------------------------------- */
1038 /** \name View Radius/Distance Utilities
1039  *
1040  * Use to calculate a distance to a point based on it's radius.
1041  * \{ */
1042
1043 float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
1044 {
1045         return radius * (1.0f / tanf(angle / 2.0f));
1046 }
1047
1048 float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
1049 {
1050         return radius / (DEFAULT_SENSOR_WIDTH / lens);
1051 }
1052
1053 /**
1054  * Return a new RegionView3D.dist value to fit the \a radius.
1055  *
1056  * \note Depth isn't taken into account, this will fit a flat plane exactly,
1057  * but points towards the view (with a perspective projection),
1058  * may be within the radius but outside the view. eg:
1059  *
1060  * <pre>
1061  *           +
1062  * pt --> + /^ radius
1063  *         / |
1064  *        /  |
1065  * view  +   +
1066  *        \  |
1067  *         \ |
1068  *          \|
1069  *           +
1070  * </pre>
1071  *
1072  * \param ar  Can be NULL if \a use_aspect is false.
1073  * \param persp  Allow the caller to tell what kind of perspective to use (ortho/view/camera)
1074  * \param use_aspect  Increase the distance to account for non 1:1 view aspect.
1075  * \param radius  The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
1076  */
1077 float ED_view3d_radius_to_dist(
1078         const View3D *v3d, const ARegion *ar,
1079         const struct Depsgraph *depsgraph,
1080         const char persp, const bool use_aspect,
1081         const float radius)
1082 {
1083         float dist;
1084
1085         BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
1086         BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
1087
1088         if (persp == RV3D_ORTHO) {
1089                 dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
1090         }
1091         else {
1092                 float lens, sensor_size, zoom;
1093                 float angle;
1094
1095                 if (persp == RV3D_CAMOB) {
1096                         CameraParams params;
1097                         BKE_camera_params_init(&params);
1098                         params.clipsta = v3d->near;
1099                         params.clipend = v3d->far;
1100                         Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
1101                         BKE_camera_params_from_object(&params, camera_eval);
1102
1103                         lens = params.lens;
1104                         sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
1105
1106                         /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
1107                         zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
1108                 }
1109                 else {
1110                         lens = v3d->lens;
1111                         sensor_size = DEFAULT_SENSOR_WIDTH;
1112                         zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
1113                 }
1114
1115                 angle = focallength_to_fov(lens, sensor_size);
1116
1117                 /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
1118                 angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
1119
1120                 dist = ED_view3d_radius_to_dist_persp(angle, radius);
1121         }
1122
1123         if (use_aspect) {
1124                 const RegionView3D *rv3d = ar->regiondata;
1125
1126                 float winx, winy;
1127
1128                 if (persp == RV3D_CAMOB) {
1129                         /* camera frame x/y in pixels */
1130                         winx = ar->winx / rv3d->viewcamtexcofac[0];
1131                         winy = ar->winy / rv3d->viewcamtexcofac[1];
1132                 }
1133                 else {
1134                         winx = ar->winx;
1135                         winy = ar->winy;
1136                 }
1137
1138                 if (winx && winy) {
1139                         float aspect = winx / winy;
1140                         if (aspect < 1.0f) {
1141                                 aspect = 1.0f / aspect;
1142                         }
1143                         dist *= aspect;
1144                 }
1145         }
1146
1147         return dist;
1148 }
1149
1150 /** \} */
1151
1152 /* -------------------------------------------------------------------- */
1153 /** \name View Distance Utilities
1154  * \{ */
1155
1156 /* problem - ofs[3] can be on same location as camera itself.
1157  * Blender needs proper dist value for zoom.
1158  * use fallback_dist to override small values
1159  */
1160 float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist)
1161 {
1162         float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1163         float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1164         float dist;
1165
1166         mul_m4_v4(mat, pos);
1167         add_v3_v3(pos, ofs);
1168         mul_m4_v4(mat, dir);
1169         normalize_v3(dir);
1170
1171         dist = dot_v3v3(pos, dir);
1172
1173         if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
1174                 dist = fallback_dist;
1175         }
1176
1177         return dist;
1178 }
1179
1180 /**
1181  * Set the dist without moving the view (compensate with #RegionView3D.ofs)
1182  *
1183  * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
1184  */
1185 void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
1186 {
1187         float viewinv[4];
1188         float tvec[3];
1189
1190         BLI_assert(dist >= 0.0f);
1191
1192         copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
1193         /* rv3d->viewinv isn't always valid */
1194 #if 0
1195         mul_mat3_m4_v3(rv3d->viewinv, tvec);
1196 #else
1197         invert_qt_qt_normalized(viewinv, rv3d->viewquat);
1198         mul_qt_v3(viewinv, tvec);
1199 #endif
1200         sub_v3_v3(rv3d->ofs, tvec);
1201
1202         rv3d->dist = dist;
1203 }
1204
1205 /** \} */
1206
1207 /* -------------------------------------------------------------------- */
1208 /** \name View Axis Utilities
1209  * \{ */
1210 static float view3d_quat_axis[6][4] = {
1211         {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f},    /* RV3D_VIEW_FRONT */
1212         {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2},   /* RV3D_VIEW_BACK */
1213         {0.5f, -0.5f, 0.5f, 0.5f},              /* RV3D_VIEW_LEFT */
1214         {0.5f, -0.5f, -0.5f, -0.5f},            /* RV3D_VIEW_RIGHT */
1215         {1.0f, 0.0f, 0.0f, 0.0f},               /* RV3D_VIEW_TOP */
1216         {0.0f, -1.0f, 0.0f, 0.0f},              /* RV3D_VIEW_BOTTOM */
1217 };
1218
1219
1220 bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
1221 {
1222         if (RV3D_VIEW_IS_AXIS(view)) {
1223                 copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
1224                 return true;
1225         }
1226         else {
1227                 return false;
1228         }
1229 }
1230
1231 char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
1232 {
1233         /* quat values are all unit length */
1234
1235         char view;
1236
1237         for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
1238                 if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) {
1239                         return view;
1240                 }
1241         }
1242
1243         return RV3D_VIEW_USER;
1244 }
1245
1246 char ED_view3d_lock_view_from_index(int index)
1247 {
1248         switch (index) {
1249                 case 0:  return RV3D_VIEW_FRONT;
1250                 case 1:  return RV3D_VIEW_TOP;
1251                 case 2:  return RV3D_VIEW_RIGHT;
1252                 default: return RV3D_VIEW_USER;
1253         }
1254
1255 }
1256
1257 char ED_view3d_axis_view_opposite(char view)
1258 {
1259         switch (view) {
1260                 case RV3D_VIEW_FRONT:   return RV3D_VIEW_BACK;
1261                 case RV3D_VIEW_BACK:    return RV3D_VIEW_FRONT;
1262                 case RV3D_VIEW_LEFT:    return RV3D_VIEW_RIGHT;
1263                 case RV3D_VIEW_RIGHT:   return RV3D_VIEW_LEFT;
1264                 case RV3D_VIEW_TOP:     return RV3D_VIEW_BOTTOM;
1265                 case RV3D_VIEW_BOTTOM:  return RV3D_VIEW_TOP;
1266         }
1267
1268         return RV3D_VIEW_USER;
1269 }
1270
1271
1272 bool ED_view3d_lock(RegionView3D *rv3d)
1273 {
1274         return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
1275 }
1276
1277 /** \} */
1278
1279 /* -------------------------------------------------------------------- */
1280 /** \name View Transform Utilities
1281  * \{ */
1282
1283 /**
1284  * Set the view transformation from a 4x4 matrix.
1285  *
1286  * \param mat The view 4x4 transformation matrix to assign.
1287  * \param ofs The view offset, normally from RegionView3D.ofs.
1288  * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
1289  * \param dist The view distance from ofs, normally from RegionView3D.dist.
1290  */
1291 void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist)
1292 {
1293         float nmat[3][3];
1294
1295         /* dist depends on offset */
1296         BLI_assert(dist == NULL || ofs != NULL);
1297
1298         copy_m3_m4(nmat, mat);
1299         normalize_m3(nmat);
1300
1301         /* Offset */
1302         if (ofs)
1303                 negate_v3_v3(ofs, mat[3]);
1304
1305         /* Quat */
1306         if (quat) {
1307                 mat3_normalized_to_quat(quat, nmat);
1308                 invert_qt_normalized(quat);
1309         }
1310
1311         if (ofs && dist) {
1312                 madd_v3_v3fl(ofs, nmat[2], *dist);
1313         }
1314 }
1315
1316 /**
1317  * Calculate the view transformation matrix from RegionView3D input.
1318  * The resulting matrix is equivalent to RegionView3D.viewinv
1319  * \param mat The view 4x4 transformation matrix to calculate.
1320  * \param ofs The view offset, normally from RegionView3D.ofs.
1321  * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
1322  * \param dist The view distance from ofs, normally from RegionView3D.dist.
1323  */
1324 void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
1325 {
1326         float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
1327         float dvec[3] = {0.0f, 0.0f, dist};
1328
1329         quat_to_mat4(mat, iviewquat);
1330         mul_mat3_m4_v3(mat, dvec);
1331         sub_v3_v3v3(mat[3], dvec, ofs);
1332 }
1333
1334 /**
1335  * Set the RegionView3D members from an objects transformation and optionally lens.
1336  * \param depsgraph The depsgraph to get the evaluated object for the lens calculation.
1337  * \param ob The object to set the view to.
1338  * \param ofs The view offset to be set, normally from RegionView3D.ofs.
1339  * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
1340  * \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
1341  * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
1342  */
1343 void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
1344 {
1345         ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
1346
1347         if (lens) {
1348                 CameraParams params;
1349
1350                 BKE_camera_params_init(&params);
1351                 BKE_camera_params_from_object(&params, ob);
1352                 *lens = params.lens;
1353         }
1354 }
1355
1356 /**
1357  * Set the object transformation from RegionView3D members.
1358  * \param depsgraph The depsgraph to get the evaluated object parent for the transformation calculation.
1359  * \param ob The object which has the transformation assigned.
1360  * \param ofs The view offset, normally from RegionView3D.ofs.
1361  * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
1362  * \param dist The view distance from ofs, normally from RegionView3D.dist.
1363  */
1364 void ED_view3d_to_object(const Depsgraph *depsgraph, Object *ob, const float ofs[3], const float quat[4], const float dist)
1365 {
1366         float mat[4][4];
1367         ED_view3d_to_m4(mat, ofs, quat, dist);
1368
1369         Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
1370         BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true);
1371 }
1372
1373 /** \} */
1374
1375 /* -------------------------------------------------------------------- */
1376 /** \name Depth Buffer Utilities
1377  * \{ */
1378
1379 float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
1380 {
1381         ViewDepths *vd = vc->rv3d->depths;
1382
1383         int x = mval[0];
1384         int y = mval[1];
1385
1386         if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
1387                 return vd->depths[y * vd->w + x];
1388         }
1389         else {
1390                 BLI_assert(1.0 <= vd->depth_range[1]);
1391                 return 1.0f;
1392         }
1393 }
1394
1395 bool ED_view3d_depth_read_cached_normal(
1396         const ViewContext *vc, const int mval[2],
1397         float r_normal[3])
1398 {
1399         /* Note: we could support passing in a radius.
1400          * For now just read 9 pixels. */
1401
1402         /* pixels surrounding */
1403         bool  depths_valid[9] = {false};
1404         float coords[9][3] = {{0}};
1405
1406         ARegion *ar = vc->ar;
1407         const ViewDepths *depths = vc->rv3d->depths;
1408
1409         for (int x = 0, i = 0; x < 2; x++) {
1410                 for (int y = 0; y < 2; y++) {
1411                         const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
1412
1413                         const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
1414                         if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
1415                                 if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) {
1416                                         depths_valid[i] = true;
1417                                 }
1418                         }
1419                         i++;
1420                 }
1421         }
1422
1423         const int edges[2][6][2] = {
1424             /* x edges */
1425             {{0, 1}, {1, 2},
1426              {3, 4}, {4, 5},
1427              {6, 7}, {7, 8}},
1428             /* y edges */
1429             {{0, 3}, {3, 6},
1430              {1, 4}, {4, 7},
1431              {2, 5}, {5, 8}},
1432         };
1433
1434         float cross[2][3] = {{0.0f}};
1435
1436         for (int i = 0; i < 6; i++) {
1437                 for (int axis = 0; axis < 2; axis++) {
1438                         if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
1439                                 float delta[3];
1440                                 sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
1441                                 add_v3_v3(cross[axis], delta);
1442                         }
1443                 }
1444         }
1445
1446         cross_v3_v3v3(r_normal, cross[0], cross[1]);
1447
1448         if (normalize_v3(r_normal) != 0.0f) {
1449                 return true;
1450         }
1451         else {
1452                 return false;
1453         }
1454 }
1455
1456 bool ED_view3d_depth_unproject(
1457         const ARegion *ar,
1458         const int mval[2], const double depth,
1459         float r_location_world[3])
1460 {
1461         float centx = (float)mval[0] + 0.5f;
1462         float centy = (float)mval[1] + 0.5f;
1463         return ED_view3d_unproject(ar, centx, centy, depth, r_location_world);
1464 }
1465
1466 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
1467 {
1468         if (rv3d->depths)
1469                 rv3d->depths->damaged = true;
1470 }
1471
1472 /** \} */