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