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