Blender  V2.93
view3d_camera_control.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
40 #include "DNA_camera_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 
44 #include "MEM_guardedalloc.h"
45 
46 #include "BLI_math.h"
47 #include "BLI_utildefines.h"
48 
49 #include "BKE_object.h"
50 
51 #include "DEG_depsgraph.h"
52 
53 #include "view3d_intern.h" /* own include */
54 
55 typedef struct View3DCameraControl {
56 
57  /* -------------------------------------------------------------------- */
58  /* Context (assign these to vars before use) */
62 
63  /* -------------------------------------------------------------------- */
64  /* internal vars */
65 
66  /* for parenting calculation */
67  float view_mat_prev[4][4];
68 
69  /* -------------------------------------------------------------------- */
70  /* optional capabilities */
71 
73 
74  /* -------------------------------------------------------------------- */
75  /* initial values */
76 
77  /* root most parent */
79 
80  /* backup values */
81  float dist_backup;
82  /* backup the views distance since we use a zero dist for fly mode */
83  float ofs_backup[3];
84  /* backup the views offset in case the user cancels flying in non camera mode */
85 
86  /* backup the views quat in case the user cancels flying in non camera mode. */
87  float rot_backup[4];
88  /* remember if we're ortho or not, only used for restoring the view if it was a ortho view */
90 
91  /* are we flying an ortho camera in perspective view,
92  * which was originally in ortho view?
93  * could probably figure it out but better be explicit */
95 
96  /* backup the objects transform */
97  void *obtfm;
99 
101 {
102  return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
103 }
104 
109 {
110  RegionView3D *rv3d = vctrl->ctx_rv3d;
111 
112  if (rv3d->persp == RV3D_CAMOB) {
113  return view3d_cameracontrol_object(vctrl);
114  }
115 
116  return NULL;
117 }
118 
124  Scene *scene,
125  View3D *v3d,
126  RegionView3D *rv3d)
127 {
128  View3DCameraControl *vctrl;
129 
130  vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
131 
132  /* Store context */
133  vctrl->ctx_scene = scene;
134  vctrl->ctx_v3d = v3d;
135  vctrl->ctx_rv3d = rv3d;
136 
137  vctrl->use_parent_root = v3d->camera != NULL &&
139 
140  vctrl->persp_backup = rv3d->persp;
141  vctrl->dist_backup = rv3d->dist;
142 
143  /* check for flying ortho camera - which we cant support well
144  * we _could_ also check for an ortho camera but this is easier */
145  if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) {
146  ((Camera *)v3d->camera->data)->type = CAM_PERSP;
147  vctrl->is_ortho_cam = true;
148  }
149 
150  if (rv3d->persp == RV3D_CAMOB) {
151  Object *ob_back;
152  if (vctrl->use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
153  while (vctrl->root_parent->parent) {
154  vctrl->root_parent = vctrl->root_parent->parent;
155  }
156  ob_back = vctrl->root_parent;
157  }
158  else {
159  ob_back = v3d->camera;
160  }
161 
162  /* store the original camera loc and rot */
163  vctrl->obtfm = BKE_object_tfm_backup(ob_back);
164 
166  negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
167 
168  rv3d->dist = 0.0;
169  }
170  else {
171  /* perspective or ortho */
172  if (rv3d->persp == RV3D_ORTHO) {
173  /* if ortho projection, make perspective */
174  rv3d->persp = RV3D_PERSP;
175  }
176 
177  copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
178  copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
179 
180  /* The dist defines a vector that is in front of the offset
181  * to rotate the view about.
182  * this is no good for fly mode because we
183  * want to rotate about the viewers center.
184  * but to correct the dist removal we must
185  * alter offset so the view doesn't jump. */
186 
187  ED_view3d_distance_set(rv3d, 0.0f);
188  /* Done with correcting for the dist */
189  }
190 
191  ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
192 
193  return vctrl;
194 }
195 
206  const float obmat[4][4],
207  const bool use_parent,
208  /* Only use when applying lock. */
209  RegionView3D *rv3d,
210  const float view_mat[4][4])
211 {
212  const bool use_protect = (ob->protectflag != 0);
213  bool view_changed = false;
214 
216  if (use_protect) {
218  }
219 
220  BKE_object_apply_mat4(ob, obmat, true, use_parent);
221 
222  if (use_protect) {
223  float obmat_noprotect[4][4], obmat_protect[4][4];
224 
225  BKE_object_to_mat4(ob, obmat_noprotect);
227  BKE_object_to_mat4(ob, obmat_protect);
228 
229  if (!equals_m4m4(obmat_noprotect, obmat_protect)) {
230  /* Apply the lock protection back to the view, without this the view
231  * keeps moving, ignoring the object locking, causing jittering in some cases. */
232  float diff_mat[4][4];
233  float view_mat_protect[4][4];
234  float obmat_noprotect_inv[4][4];
235  invert_m4_m4(obmat_noprotect_inv, obmat_noprotect);
236  mul_m4_m4m4(diff_mat, obmat_protect, obmat_noprotect_inv);
237 
238  mul_m4_m4m4(view_mat_protect, diff_mat, view_mat);
239  ED_view3d_from_m4(view_mat_protect, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
240  view_changed = true;
241  }
242  }
243  return view_changed;
244 }
245 
250  /* args for keyframing */
251  const bool use_autokey,
252  struct bContext *C,
253  const bool do_rotate,
254  const bool do_translate)
255 {
256  /* We are in camera view so apply the view offset and rotation to the view matrix
257  * and set the camera to the view. */
258 
259  Scene *scene = vctrl->ctx_scene;
260  View3D *v3d = vctrl->ctx_v3d;
261  RegionView3D *rv3d = vctrl->ctx_rv3d;
262 
263  ID *id_key;
264 
265  float view_mat[4][4];
266  ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
267 
268  /* transform the parent or the camera? */
269  if (vctrl->root_parent) {
270  Object *ob_update;
271 
272  float prev_view_imat[4][4];
273  float diff_mat[4][4];
274  float parent_mat[4][4];
275 
276  invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
277  mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
278  mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
279 
280  if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) {
281  /* Calculate again since the view locking changes the matrix. */
282  ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
283  }
284 
285  ob_update = v3d->camera->parent;
286  while (ob_update) {
288  ob_update = ob_update->parent;
289  }
290 
291  copy_m4_m4(vctrl->view_mat_prev, view_mat);
292 
293  id_key = &vctrl->root_parent->id;
294  }
295  else {
296  float scale_mat[4][4];
297  float scale_back[3];
298 
299  /* even though we handle the scale matrix, this still changes over time */
300  copy_v3_v3(scale_back, v3d->camera->scale);
301 
302  size_to_mat4(scale_mat, v3d->camera->scale);
303  mul_m4_m4m4(view_mat, view_mat, scale_mat);
304 
305  object_apply_mat4_with_protect(v3d->camera, view_mat, true, rv3d, view_mat);
306 
308 
309  copy_v3_v3(v3d->camera->scale, scale_back);
310 
311  id_key = &v3d->camera->id;
312  }
313 
314  /* record the motion */
315  if (use_autokey) {
316  ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
317  }
318 }
319 
326 void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
327 {
328  View3D *v3d = vctrl->ctx_v3d;
329  RegionView3D *rv3d = vctrl->ctx_rv3d;
330 
331  if (restore) {
332  /* Revert to original view? */
333  if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
334  Object *ob_back = view3d_cameracontrol_object(vctrl);
335 
336  /* store the original camera loc and rot */
337  BKE_object_tfm_restore(ob_back, vctrl->obtfm);
338 
340  }
341  else {
342  /* Non Camera we need to reset the view back
343  * to the original location because the user canceled. */
344  copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
345  rv3d->persp = vctrl->persp_backup;
346  }
347  /* always, is set to zero otherwise */
348  copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
349  rv3d->dist = vctrl->dist_backup;
350  }
351  else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
353 
354  /* always, is set to zero otherwise */
355  copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
356  rv3d->dist = vctrl->dist_backup;
357  }
358  else { /* not camera */
359  /* Apply the fly mode view */
360  /* restore the dist */
361  ED_view3d_distance_set(rv3d, vctrl->dist_backup);
362  /* Done with correcting for the dist */
363  }
364 
365  if (vctrl->is_ortho_cam) {
366  ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
367  }
368 
369  if (vctrl->obtfm) {
370  MEM_freeN(vctrl->obtfm);
371  }
372 
373  MEM_freeN(vctrl);
374 }
General operations, lookup, etc. for blender objects.
void BKE_object_tfm_restore(struct Object *ob, void *obtfm_pt)
Definition: object.c:4273
void * BKE_object_tfm_backup(struct Object *ob)
Definition: object.c:4250
void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob)
Definition: object.c:3653
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4])
Definition: object.c:3234
void BKE_object_tfm_protected_backup(const struct Object *ob, ObjectTfmProtectedChannels *obtfm)
void BKE_object_apply_mat4(struct Object *ob, const float mat[4][4], const bool use_compat, const bool use_parent)
Definition: object.c:3754
void BKE_object_tfm_protected_restore(struct Object *ob, const ObjectTfmProtectedChannels *obtfm, const short protectflag)
Definition: object.c:3158
#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:262
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void size_to_mat4(float R[4][4], const float size[3])
Definition: math_matrix.c:2118
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
Definition: math_matrix.c:2612
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:52
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:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ 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_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist)
bool ED_view3d_camera_autokey(const struct Scene *scene, struct ID *id_key, struct bContext *C, const bool do_rotate, const bool do_translate)
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
Scene scene
const Depsgraph * depsgraph
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
Definition: DNA_ID.h:273
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)