Blender  V3.3
view3d_camera_control.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
26 #include "DNA_camera_types.h"
27 #include "DNA_object_types.h"
28 #include "DNA_scene_types.h"
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34 
35 #include "BKE_object.h"
36 
37 #include "DEG_depsgraph.h"
38 
39 #include "view3d_intern.h" /* own include */
40 
41 typedef struct View3DCameraControl {
42 
43  /* -------------------------------------------------------------------- */
44  /* Context (assign these to vars before use) */
48 
49  /* -------------------------------------------------------------------- */
50  /* internal vars */
51 
52  /* for parenting calculation */
53  float view_mat_prev[4][4];
54 
55  /* -------------------------------------------------------------------- */
56  /* optional capabilities */
57 
59 
60  /* -------------------------------------------------------------------- */
61  /* initial values */
62 
63  /* root most parent */
65 
66  /* backup values */
67  float dist_backup;
68  /* backup the views distance since we use a zero dist for fly mode */
69  float ofs_backup[3];
70  /* backup the views offset in case the user cancels flying in non camera mode */
71 
72  /* backup the views quat in case the user cancels flying in non camera mode. */
73  float rot_backup[4];
74  /* remember if we're ortho or not, only used for restoring the view if it was a ortho view */
76 
77  /* are we flying an ortho camera in perspective view,
78  * which was originally in ortho view?
79  * could probably figure it out but better be explicit */
81 
82  /* backup the objects transform */
83  void *obtfm;
85 
87 {
88  return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
89 }
90 
92 {
93  RegionView3D *rv3d = vctrl->ctx_rv3d;
94 
95  if (rv3d->persp == RV3D_CAMOB) {
96  return view3d_cameracontrol_object(vctrl);
97  }
98 
99  return NULL;
100 }
101 
103  Scene *scene,
104  View3D *v3d,
105  RegionView3D *rv3d)
106 {
107  View3DCameraControl *vctrl;
108 
109  vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
110 
111  /* Store context */
112  vctrl->ctx_scene = scene;
113  vctrl->ctx_v3d = v3d;
114  vctrl->ctx_rv3d = rv3d;
115 
116  vctrl->use_parent_root = v3d->camera != NULL &&
118 
119  vctrl->persp_backup = rv3d->persp;
120  vctrl->dist_backup = rv3d->dist;
121 
122  /* check for flying ortho camera - which we can't support well
123  * we _could_ also check for an ortho camera but this is easier */
124  if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) {
125  ((Camera *)v3d->camera->data)->type = CAM_PERSP;
126  vctrl->is_ortho_cam = true;
127  }
128 
129  if (rv3d->persp == RV3D_CAMOB) {
130  Object *ob_back;
131  if (vctrl->use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
132  while (vctrl->root_parent->parent) {
133  vctrl->root_parent = vctrl->root_parent->parent;
134  }
135  ob_back = vctrl->root_parent;
136  }
137  else {
138  ob_back = v3d->camera;
139  }
140 
141  /* store the original camera loc and rot */
142  vctrl->obtfm = BKE_object_tfm_backup(ob_back);
143 
145  negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
146 
147  rv3d->dist = 0.0;
148  }
149  else {
150  /* perspective or ortho */
151  if (rv3d->persp == RV3D_ORTHO) {
152  /* if ortho projection, make perspective */
153  rv3d->persp = RV3D_PERSP;
154  }
155 
156  copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
157  copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
158 
159  /* The dist defines a vector that is in front of the offset
160  * to rotate the view about.
161  * this is no good for fly mode because we
162  * want to rotate about the viewers center.
163  * but to correct the dist removal we must
164  * alter offset so the view doesn't jump. */
165 
166  ED_view3d_distance_set(rv3d, 0.0f);
167  /* Done with correcting for the dist */
168  }
169 
170  ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
171 
172  return vctrl;
173 }
174 
185  const float obmat[4][4],
186  const bool use_parent,
187  /* Only use when applying lock. */
188  RegionView3D *rv3d,
189  const float view_mat[4][4])
190 {
191  const bool use_protect = (ob->protectflag != 0);
192  bool view_changed = false;
193 
195  if (use_protect) {
197  }
198 
199  BKE_object_apply_mat4(ob, obmat, true, use_parent);
200 
201  if (use_protect) {
202  float obmat_noprotect[4][4], obmat_protect[4][4];
203 
204  BKE_object_to_mat4(ob, obmat_noprotect);
206  BKE_object_to_mat4(ob, obmat_protect);
207 
208  if (!equals_m4m4(obmat_noprotect, obmat_protect)) {
209  /* Apply the lock protection back to the view, without this the view
210  * keeps moving, ignoring the object locking, causing jittering in some cases. */
211  float diff_mat[4][4];
212  float view_mat_protect[4][4];
213  float obmat_noprotect_inv[4][4];
214  invert_m4_m4(obmat_noprotect_inv, obmat_noprotect);
215  mul_m4_m4m4(diff_mat, obmat_protect, obmat_noprotect_inv);
216 
217  mul_m4_m4m4(view_mat_protect, diff_mat, view_mat);
218  ED_view3d_from_m4(view_mat_protect, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
219  view_changed = true;
220  }
221  }
222  return view_changed;
223 }
224 
226  /* args for keyframing */
227  const bool use_autokey,
228  struct bContext *C,
229  const bool do_rotate,
230  const bool do_translate)
231 {
232  /* We are in camera view so apply the view offset and rotation to the view matrix
233  * and set the camera to the view. */
234 
235  Scene *scene = vctrl->ctx_scene;
236  View3D *v3d = vctrl->ctx_v3d;
237  RegionView3D *rv3d = vctrl->ctx_rv3d;
238 
239  ID *id_key;
240 
241  float view_mat[4][4];
242  ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
243 
244  /* transform the parent or the camera? */
245  if (vctrl->root_parent) {
246  Object *ob_update;
247 
248  float prev_view_imat[4][4];
249  float diff_mat[4][4];
250  float parent_mat[4][4];
251 
252  invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
253  mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
254  mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
255 
256  if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) {
257  /* Calculate again since the view locking changes the matrix. */
258  ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
259  }
260 
261  ob_update = v3d->camera->parent;
262  while (ob_update) {
264  ob_update = ob_update->parent;
265  }
266 
267  copy_m4_m4(vctrl->view_mat_prev, view_mat);
268 
269  id_key = &vctrl->root_parent->id;
270  }
271  else {
272  float scale_mat[4][4];
273  float scale_back[3];
274 
275  /* even though we handle the scale matrix, this still changes over time */
276  copy_v3_v3(scale_back, v3d->camera->scale);
277 
278  size_to_mat4(scale_mat, v3d->camera->scale);
279  mul_m4_m4m4(view_mat, view_mat, scale_mat);
280 
281  object_apply_mat4_with_protect(v3d->camera, view_mat, true, rv3d, view_mat);
282 
284 
285  copy_v3_v3(v3d->camera->scale, scale_back);
286 
287  id_key = &v3d->camera->id;
288  }
289 
290  /* record the motion */
291  if (use_autokey) {
292  ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
293  }
294 }
295 
296 void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
297 {
298  View3D *v3d = vctrl->ctx_v3d;
299  RegionView3D *rv3d = vctrl->ctx_rv3d;
300 
301  if (restore) {
302  /* Revert to original view? */
303  if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
304  Object *ob_back = view3d_cameracontrol_object(vctrl);
305 
306  /* store the original camera loc and rot */
307  BKE_object_tfm_restore(ob_back, vctrl->obtfm);
308 
310  }
311  else {
312  /* Non Camera we need to reset the view back
313  * to the original location because the user canceled. */
314  copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
315  rv3d->persp = vctrl->persp_backup;
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 if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
323 
324  /* always, is set to zero otherwise */
325  copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
326  rv3d->dist = vctrl->dist_backup;
327  }
328  else { /* not camera */
329  /* Apply the fly mode view */
330  /* restore the dist */
331  ED_view3d_distance_set(rv3d, vctrl->dist_backup);
332  /* Done with correcting for the dist */
333  }
334 
335  if (vctrl->is_ortho_cam) {
336  ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
337  }
338 
339  if (vctrl->obtfm) {
340  MEM_freeN(vctrl->obtfm);
341  }
342 
343  MEM_freeN(vctrl);
344 }
General operations, lookup, etc. for blender objects.
void BKE_object_tfm_restore(struct Object *ob, void *obtfm_pt)
Definition: object.cc:4242
void BKE_object_tfm_protected_restore(struct Object *ob, const ObjectTfmProtectedChannels *obtfm, short protectflag)
Definition: object.cc:3007
void * BKE_object_tfm_backup(struct Object *ob)
Definition: object.cc:4219
void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob)
Definition: object.cc:3495
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4])
Definition: object.cc:3082
void BKE_object_apply_mat4(struct Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
Definition: object.cc:3575
void BKE_object_tfm_protected_backup(const struct Object *ob, ObjectTfmProtectedChannels *obtfm)
#define BLI_INLINE
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void size_to_mat4(float R[4][4], const float size[3])
Definition: math_matrix.c:2111
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
Definition: math_matrix.c:2531
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:33
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ CAM_PERSP
@ CAM_ORTHO
Object is a sort of wrapper for general info.
@ OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK
#define RV3D_CAMOB
#define RV3D_PERSP
#define RV3D_ORTHO
void ED_view3d_distance_set(struct RegionView3D *rv3d, float dist)
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist)
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
bool ED_view3d_camera_autokey(const struct Scene *scene, struct ID *id_key, struct bContext *C, bool do_rotate, bool do_translate)
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
Scene scene
const Depsgraph * depsgraph
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
Definition: DNA_ID.h:368
short transflag
float scale[3]
float obmat[4][4]
short protectflag
struct Object * parent
void * data
float viewquat[4]
struct Object * camera
BLI_INLINE Object * view3d_cameracontrol_object(const View3DCameraControl *vctrl)
struct View3DCameraControl View3DCameraControl
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, const bool use_autokey, struct bContext *C, const bool do_rotate, const bool do_translate)
Object * ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
static bool object_apply_mat4_with_protect(Object *ob, const float obmat[4][4], const bool use_parent, RegionView3D *rv3d, const float view_mat[4][4])
struct View3DCameraControl * ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d)
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)