Pass EvaluationContext argument everywhere
[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_control_acquire).
35  * - modify ``rv3d->ofs``, ``rv3d->viewquat``.
36  * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport.
37  * - finish and release the view-control (#ED_view3d_control_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         /* intial 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         const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d,
142         const bool use_parent_root)
143 {
144         View3DCameraControl *vctrl;
145         EvaluationContext eval_ctx;
146
147         CTX_data_eval_ctx(C, &eval_ctx);
148
149         vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
150
151         /* Store context */
152         vctrl->ctx_scene = scene;
153         vctrl->ctx_v3d = v3d;
154         vctrl->ctx_rv3d = rv3d;
155
156         vctrl->use_parent_root = use_parent_root;
157
158         vctrl->persp_backup = rv3d->persp;
159         vctrl->dist_backup = rv3d->dist;
160
161         /* check for flying ortho camera - which we cant support well
162          * we _could_ also check for an ortho camera but this is easier */
163         if ((rv3d->persp == RV3D_CAMOB) &&
164             (rv3d->is_persp == false))
165         {
166                 ((Camera *)v3d->camera->data)->type = CAM_PERSP;
167                 vctrl->is_ortho_cam = true;
168         }
169
170         if (rv3d->persp == RV3D_CAMOB) {
171                 Object *ob_back;
172                 if (use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
173                         while (vctrl->root_parent->parent)
174                                 vctrl->root_parent = vctrl->root_parent->parent;
175                         ob_back = vctrl->root_parent;
176                 }
177                 else {
178                         ob_back = v3d->camera;
179                 }
180
181                 /* store the original camera loc and rot */
182                 vctrl->obtfm = BKE_object_tfm_backup(ob_back);
183
184                 BKE_object_where_is_calc(&eval_ctx, scene, v3d->camera);
185                 negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
186
187                 rv3d->dist = 0.0;
188         }
189         else {
190                 /* perspective or ortho */
191                 if (rv3d->persp == RV3D_ORTHO)
192                         rv3d->persp = RV3D_PERSP;  /* if ortho projection, make perspective */
193
194                 copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
195                 copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
196
197                 /* the dist defines a vector that is infront of the offset
198                  * to rotate the view about.
199                  * this is no good for fly mode because we
200                  * want to rotate about the viewers center.
201                  * but to correct the dist removal we must
202                  * alter offset so the view doesn't jump. */
203
204                 ED_view3d_distance_set(rv3d, 0.0f);
205                 /* Done with correcting for the dist */
206         }
207
208         ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
209
210         return vctrl;
211 }
212
213
214 /**
215  * Updates cameras from the ``rv3d`` values, optionally auto-keyframing.
216  */
217 void ED_view3d_cameracontrol_update(
218         View3DCameraControl *vctrl,
219         /* args for keyframing */
220         const bool use_autokey,
221         struct bContext *C, const bool do_rotate, const bool do_translate)
222 {
223         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
224
225         Scene *scene       = vctrl->ctx_scene;
226         View3D *v3d        = vctrl->ctx_v3d;
227         RegionView3D *rv3d = vctrl->ctx_rv3d;
228
229         ID *id_key;
230
231         /* transform the parent or the camera? */
232         if (vctrl->root_parent) {
233                 Object *ob_update;
234
235                 float view_mat[4][4];
236                 float prev_view_imat[4][4];
237                 float diff_mat[4][4];
238                 float parent_mat[4][4];
239
240                 invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
241                 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
242                 mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
243                 mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
244
245                 BKE_object_apply_mat4(vctrl->root_parent, parent_mat, true, false);
246
247                 ob_update = v3d->camera->parent;
248                 while (ob_update) {
249                         DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
250                         ob_update = ob_update->parent;
251                 }
252
253                 copy_m4_m4(vctrl->view_mat_prev, view_mat);
254
255                 id_key = &vctrl->root_parent->id;
256         }
257         else {
258                 float view_mat[4][4];
259                 float size_mat[4][4];
260                 float size_back[3];
261
262                 /* even though we handle the size matrix, this still changes over time */
263                 copy_v3_v3(size_back, v3d->camera->size);
264
265                 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
266                 size_to_mat4(size_mat, v3d->camera->size);
267                 mul_m4_m4m4(view_mat, view_mat, size_mat);
268
269                 BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
270
271                 DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
272
273                 copy_v3_v3(v3d->camera->size, size_back);
274
275                 id_key = &v3d->camera->id;
276         }
277
278         /* record the motion */
279         if (use_autokey) {
280                 ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
281         }
282 }
283
284
285 /**
286  * Release view control.
287  *
288  * \param restore  Sets the view state to the values that were set
289  *                 before #ED_view3d_control_acquire was called.
290  */
291 void ED_view3d_cameracontrol_release(
292         View3DCameraControl *vctrl,
293         const bool restore)
294 {
295         View3D *v3d        = vctrl->ctx_v3d;
296         RegionView3D *rv3d = vctrl->ctx_rv3d;
297
298         if (restore) {
299                 /* Revert to original view? */
300                 if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
301                         Object *ob_back = view3d_cameracontrol_object(vctrl);
302
303                         /* store the original camera loc and rot */
304                         BKE_object_tfm_restore(ob_back, vctrl->obtfm);
305
306                         DEG_id_tag_update(&ob_back->id, OB_RECALC_OB);
307                 }
308                 else {
309                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
310                         copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
311                         rv3d->persp = vctrl->persp_backup;
312                 }
313                 /* always, is set to zero otherwise */
314                 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
315                 rv3d->dist = vctrl->dist_backup;
316         }
317         else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
318                 DEG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB);
319
320                 /* always, is set to zero otherwise */
321                 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
322                 rv3d->dist = vctrl->dist_backup;
323         }
324         else { /* not camera */
325                 /* Apply the fly mode view */
326                 /* restore the dist */
327                 ED_view3d_distance_set(rv3d, vctrl->dist_backup);
328                 /* Done with correcting for the dist */
329         }
330
331         if (vctrl->is_ortho_cam) {
332                 ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
333         }
334
335         if (vctrl->obtfm) {
336                 MEM_freeN(vctrl->obtfm);
337         }
338
339         MEM_freeN(vctrl);
340 }