Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / view3d_camera_control.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  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_view3d/view3d_camera_control.c
24  *  \ingroup spview3d
25  *
26  * The purpose of View3DCameraControl is to allow editing \a rv3d manipulation
27  * (mainly \a ofs and \a viewquat) for the purpose of view navigation
28  * without having to worry about positioning the camera, its parent...
29  * or other details.
30  *
31  *
32  * Typical view-control usage:
33  *
34  * - acquire a view-control (#ED_view3d_cameracontrol_acquire).
35  * - modify ``rv3d->ofs``, ``rv3d->viewquat``.
36  * - update the view data (#ED_view3d_cameracontrol_acquire) - within a loop which draws the viewport.
37  * - finish and release the view-control (#ED_view3d_cameracontrol_release),
38  *   either keeping the current view or restoring the initial view.
39  *
40  * Notes:
41  *
42  * - when acquiring ``rv3d->dist`` is set to zero
43  *   (so ``rv3d->ofs`` is always the view-point)
44  * - updating can optionally keyframe the camera object.
45  */
46
47 #include "DNA_scene_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_camera_types.h"
50
51 #include "MEM_guardedalloc.h"
52
53 #include "BLI_math.h"
54 #include "BLI_utildefines.h"
55
56 #include "BKE_object.h"
57 #include "BKE_context.h"
58
59 #include "DEG_depsgraph.h"
60
61 #include "ED_screen.h"
62
63 #include "view3d_intern.h"  /* own include */
64
65 #include "BLI_strict_flags.h"
66
67
68 typedef struct View3DCameraControl {
69
70         /* -------------------------------------------------------------------- */
71         /* Context (assign these to vars before use) */
72         Scene        *ctx_scene;
73         View3D       *ctx_v3d;
74         RegionView3D *ctx_rv3d;
75
76
77         /* -------------------------------------------------------------------- */
78         /* internal vars */
79
80         /* for parenting calculation */
81         float view_mat_prev[4][4];
82
83
84         /* -------------------------------------------------------------------- */
85         /* optional capabilities */
86
87         bool use_parent_root;
88
89
90         /* -------------------------------------------------------------------- */
91         /* initial values */
92
93         /* root most parent */
94         Object *root_parent;
95
96         /* backup values */
97         float dist_backup; /* backup the views distance since we use a zero dist for fly mode */
98         float ofs_backup[3]; /* backup the views offset in case the user cancels flying in non camera mode */
99
100         /* backup the views quat in case the user cancels flying in non camera mode.
101          * (quat for view, eul for camera) */
102         float rot_backup[4];
103         char persp_backup;  /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
104
105         /* are we flying an ortho camera in perspective view,
106          * which was originally in ortho view?
107          * could probably figure it out but better be explicit */
108         bool is_ortho_cam;
109
110         void *obtfm; /* backup the objects transform */
111 } View3DCameraControl;
112
113
114 BLI_INLINE Object *view3d_cameracontrol_object(View3DCameraControl *vctrl)
115 {
116         return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
117 }
118
119
120 /**
121  * Returns the object which is being manipulated or NULL.
122  */
123 Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
124 {
125         RegionView3D *rv3d = vctrl->ctx_rv3d;
126
127         if (rv3d->persp == RV3D_CAMOB) {
128                 return view3d_cameracontrol_object(vctrl);
129         }
130         else {
131                 return NULL;
132         }
133 }
134
135
136 /**
137  * Creates a #View3DCameraControl handle and sets up
138  * the view for first-person style navigation.
139  */
140 struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
141         Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d,
142         const bool use_parent_root)
143 {
144         View3DCameraControl *vctrl;
145
146         vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
147
148         /* Store context */
149         vctrl->ctx_scene = scene;
150         vctrl->ctx_v3d = v3d;
151         vctrl->ctx_rv3d = rv3d;
152
153         vctrl->use_parent_root = use_parent_root;
154
155         vctrl->persp_backup = rv3d->persp;
156         vctrl->dist_backup = rv3d->dist;
157
158         /* check for flying ortho camera - which we cant support well
159          * we _could_ also check for an ortho camera but this is easier */
160         if ((rv3d->persp == RV3D_CAMOB) &&
161             (rv3d->is_persp == false))
162         {
163                 ((Camera *)v3d->camera->data)->type = CAM_PERSP;
164                 vctrl->is_ortho_cam = true;
165         }
166
167         if (rv3d->persp == RV3D_CAMOB) {
168                 Object *ob_back;
169                 if (use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
170                         while (vctrl->root_parent->parent)
171                                 vctrl->root_parent = vctrl->root_parent->parent;
172                         ob_back = vctrl->root_parent;
173                 }
174                 else {
175                         ob_back = v3d->camera;
176                 }
177
178                 /* store the original camera loc and rot */
179                 vctrl->obtfm = BKE_object_tfm_backup(ob_back);
180
181                 BKE_object_where_is_calc(depsgraph, scene, v3d->camera);
182                 negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
183
184                 rv3d->dist = 0.0;
185         }
186         else {
187                 /* perspective or ortho */
188                 if (rv3d->persp == RV3D_ORTHO)
189                         rv3d->persp = RV3D_PERSP;  /* if ortho projection, make perspective */
190
191                 copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
192                 copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
193
194                 /* the dist defines a vector that is infront of the offset
195                  * to rotate the view about.
196                  * this is no good for fly mode because we
197                  * want to rotate about the viewers center.
198                  * but to correct the dist removal we must
199                  * alter offset so the view doesn't jump. */
200
201                 ED_view3d_distance_set(rv3d, 0.0f);
202                 /* Done with correcting for the dist */
203         }
204
205         ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
206
207         return vctrl;
208 }
209
210
211 /**
212  * Updates cameras from the ``rv3d`` values, optionally auto-keyframing.
213  */
214 void ED_view3d_cameracontrol_update(
215         View3DCameraControl *vctrl,
216         /* args for keyframing */
217         const bool use_autokey,
218         struct bContext *C, const bool do_rotate, const bool do_translate)
219 {
220         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
221
222         Scene *scene       = vctrl->ctx_scene;
223         View3D *v3d        = vctrl->ctx_v3d;
224         RegionView3D *rv3d = vctrl->ctx_rv3d;
225
226         ID *id_key;
227
228         /* transform the parent or the camera? */
229         if (vctrl->root_parent) {
230                 Object *ob_update;
231
232                 float view_mat[4][4];
233                 float prev_view_imat[4][4];
234                 float diff_mat[4][4];
235                 float parent_mat[4][4];
236
237                 invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
238                 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
239                 mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
240                 mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
241
242                 BKE_object_apply_mat4(vctrl->root_parent, parent_mat, true, false);
243
244                 ob_update = v3d->camera->parent;
245                 while (ob_update) {
246                         DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
247                         ob_update = ob_update->parent;
248                 }
249
250                 copy_m4_m4(vctrl->view_mat_prev, view_mat);
251
252                 id_key = &vctrl->root_parent->id;
253         }
254         else {
255                 float view_mat[4][4];
256                 float size_mat[4][4];
257                 float size_back[3];
258
259                 /* even though we handle the size matrix, this still changes over time */
260                 copy_v3_v3(size_back, v3d->camera->size);
261
262                 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
263                 size_to_mat4(size_mat, v3d->camera->size);
264                 mul_m4_m4m4(view_mat, view_mat, size_mat);
265
266                 BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
267
268                 DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
269
270                 copy_v3_v3(v3d->camera->size, size_back);
271
272                 id_key = &v3d->camera->id;
273         }
274
275         /* record the motion */
276         if (use_autokey) {
277                 ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
278         }
279 }
280
281
282 /**
283  * Release view control.
284  *
285  * \param restore  Sets the view state to the values that were set
286  *                 before #ED_view3d_control_acquire was called.
287  */
288 void ED_view3d_cameracontrol_release(
289         View3DCameraControl *vctrl,
290         const bool restore)
291 {
292         View3D *v3d        = vctrl->ctx_v3d;
293         RegionView3D *rv3d = vctrl->ctx_rv3d;
294
295         if (restore) {
296                 /* Revert to original view? */
297                 if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
298                         Object *ob_back = view3d_cameracontrol_object(vctrl);
299
300                         /* store the original camera loc and rot */
301                         BKE_object_tfm_restore(ob_back, vctrl->obtfm);
302
303                         DEG_id_tag_update(&ob_back->id, OB_RECALC_OB);
304                 }
305                 else {
306                         /* Non Camera we need to reset the view back to the original location because the user canceled*/
307                         copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
308                         rv3d->persp = vctrl->persp_backup;
309                 }
310                 /* always, is set to zero otherwise */
311                 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
312                 rv3d->dist = vctrl->dist_backup;
313         }
314         else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
315                 DEG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB);
316
317                 /* always, is set to zero otherwise */
318                 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
319                 rv3d->dist = vctrl->dist_backup;
320         }
321         else { /* not camera */
322                 /* Apply the fly mode view */
323                 /* restore the dist */
324                 ED_view3d_distance_set(rv3d, vctrl->dist_backup);
325                 /* Done with correcting for the dist */
326         }
327
328         if (vctrl->is_ortho_cam) {
329                 ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
330         }
331
332         if (vctrl->obtfm) {
333                 MEM_freeN(vctrl->obtfm);
334         }
335
336         MEM_freeN(vctrl);
337 }