This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/editors/space_view3d/view3d_camera_control.c
Brecht Van Lommel 34ab90f546 Depsgraph: remove EvaluationContext, pass Depsgraph instead.
The depsgraph was always created within a fixed evaluation context. Passing
both risks the depsgraph and evaluation context not matching, and it
complicates the Python API where we'd have to expose both which is not so
easy to understand.

This also removes the global evaluation context in main, which assumed there
to be a single active scene and view layer.

Differential Revision: https://developer.blender.org/D3152
2018-04-16 19:55:33 +02:00

338 lines
9.4 KiB
C

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_view3d/view3d_camera_control.c
* \ingroup spview3d
*
* The purpose of View3DCameraControl is to allow editing \a rv3d manipulation
* (mainly \a ofs and \a viewquat) for the purpose of view navigation
* without having to worry about positioning the camera, its parent...
* or other details.
*
*
* Typical view-control usage:
*
* - acquire a view-control (#ED_view3d_cameracontrol_acquire).
* - modify ``rv3d->ofs``, ``rv3d->viewquat``.
* - update the view data (#ED_view3d_cameracontrol_acquire) - within a loop which draws the viewport.
* - finish and release the view-control (#ED_view3d_cameracontrol_release),
* either keeping the current view or restoring the initial view.
*
* Notes:
*
* - when acquiring ``rv3d->dist`` is set to zero
* (so ``rv3d->ofs`` is always the view-point)
* - updating can optionally keyframe the camera object.
*/
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_camera_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "DEG_depsgraph.h"
#include "ED_screen.h"
#include "view3d_intern.h" /* own include */
#include "BLI_strict_flags.h"
typedef struct View3DCameraControl {
/* -------------------------------------------------------------------- */
/* Context (assign these to vars before use) */
Scene *ctx_scene;
View3D *ctx_v3d;
RegionView3D *ctx_rv3d;
/* -------------------------------------------------------------------- */
/* internal vars */
/* for parenting calculation */
float view_mat_prev[4][4];
/* -------------------------------------------------------------------- */
/* optional capabilities */
bool use_parent_root;
/* -------------------------------------------------------------------- */
/* intial values */
/* root most parent */
Object *root_parent;
/* backup values */
float dist_backup; /* backup the views distance since we use a zero dist for fly mode */
float ofs_backup[3]; /* backup the views offset in case the user cancels flying in non camera mode */
/* backup the views quat in case the user cancels flying in non camera mode.
* (quat for view, eul for camera) */
float rot_backup[4];
char persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
/* are we flying an ortho camera in perspective view,
* which was originally in ortho view?
* could probably figure it out but better be explicit */
bool is_ortho_cam;
void *obtfm; /* backup the objects transform */
} View3DCameraControl;
BLI_INLINE Object *view3d_cameracontrol_object(View3DCameraControl *vctrl)
{
return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
}
/**
* Returns the object which is being manipulated or NULL.
*/
Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
{
RegionView3D *rv3d = vctrl->ctx_rv3d;
if (rv3d->persp == RV3D_CAMOB) {
return view3d_cameracontrol_object(vctrl);
}
else {
return NULL;
}
}
/**
* Creates a #View3DCameraControl handle and sets up
* the view for first-person style navigation.
*/
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root)
{
View3DCameraControl *vctrl;
vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
/* Store context */
vctrl->ctx_scene = scene;
vctrl->ctx_v3d = v3d;
vctrl->ctx_rv3d = rv3d;
vctrl->use_parent_root = use_parent_root;
vctrl->persp_backup = rv3d->persp;
vctrl->dist_backup = rv3d->dist;
/* check for flying ortho camera - which we cant support well
* we _could_ also check for an ortho camera but this is easier */
if ((rv3d->persp == RV3D_CAMOB) &&
(rv3d->is_persp == false))
{
((Camera *)v3d->camera->data)->type = CAM_PERSP;
vctrl->is_ortho_cam = true;
}
if (rv3d->persp == RV3D_CAMOB) {
Object *ob_back;
if (use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
while (vctrl->root_parent->parent)
vctrl->root_parent = vctrl->root_parent->parent;
ob_back = vctrl->root_parent;
}
else {
ob_back = v3d->camera;
}
/* store the original camera loc and rot */
vctrl->obtfm = BKE_object_tfm_backup(ob_back);
BKE_object_where_is_calc(depsgraph, scene, v3d->camera);
negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
rv3d->dist = 0.0;
}
else {
/* perspective or ortho */
if (rv3d->persp == RV3D_ORTHO)
rv3d->persp = RV3D_PERSP; /* if ortho projection, make perspective */
copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
/* the dist defines a vector that is infront of the offset
* to rotate the view about.
* this is no good for fly mode because we
* want to rotate about the viewers center.
* but to correct the dist removal we must
* alter offset so the view doesn't jump. */
ED_view3d_distance_set(rv3d, 0.0f);
/* Done with correcting for the dist */
}
ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
return vctrl;
}
/**
* Updates cameras from the ``rv3d`` values, optionally auto-keyframing.
*/
void ED_view3d_cameracontrol_update(
View3DCameraControl *vctrl,
/* args for keyframing */
const bool use_autokey,
struct bContext *C, const bool do_rotate, const bool do_translate)
{
/* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
Scene *scene = vctrl->ctx_scene;
View3D *v3d = vctrl->ctx_v3d;
RegionView3D *rv3d = vctrl->ctx_rv3d;
ID *id_key;
/* transform the parent or the camera? */
if (vctrl->root_parent) {
Object *ob_update;
float view_mat[4][4];
float prev_view_imat[4][4];
float diff_mat[4][4];
float parent_mat[4][4];
invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
BKE_object_apply_mat4(vctrl->root_parent, parent_mat, true, false);
ob_update = v3d->camera->parent;
while (ob_update) {
DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
ob_update = ob_update->parent;
}
copy_m4_m4(vctrl->view_mat_prev, view_mat);
id_key = &vctrl->root_parent->id;
}
else {
float view_mat[4][4];
float size_mat[4][4];
float size_back[3];
/* even though we handle the size matrix, this still changes over time */
copy_v3_v3(size_back, v3d->camera->size);
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
size_to_mat4(size_mat, v3d->camera->size);
mul_m4_m4m4(view_mat, view_mat, size_mat);
BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
copy_v3_v3(v3d->camera->size, size_back);
id_key = &v3d->camera->id;
}
/* record the motion */
if (use_autokey) {
ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
}
}
/**
* Release view control.
*
* \param restore Sets the view state to the values that were set
* before #ED_view3d_control_acquire was called.
*/
void ED_view3d_cameracontrol_release(
View3DCameraControl *vctrl,
const bool restore)
{
View3D *v3d = vctrl->ctx_v3d;
RegionView3D *rv3d = vctrl->ctx_rv3d;
if (restore) {
/* Revert to original view? */
if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
Object *ob_back = view3d_cameracontrol_object(vctrl);
/* store the original camera loc and rot */
BKE_object_tfm_restore(ob_back, vctrl->obtfm);
DEG_id_tag_update(&ob_back->id, OB_RECALC_OB);
}
else {
/* Non Camera we need to reset the view back to the original location bacause the user canceled*/
copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
rv3d->persp = vctrl->persp_backup;
}
/* always, is set to zero otherwise */
copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
rv3d->dist = vctrl->dist_backup;
}
else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
DEG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB);
/* always, is set to zero otherwise */
copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
rv3d->dist = vctrl->dist_backup;
}
else { /* not camera */
/* Apply the fly mode view */
/* restore the dist */
ED_view3d_distance_set(rv3d, vctrl->dist_backup);
/* Done with correcting for the dist */
}
if (vctrl->is_ortho_cam) {
((Camera *)v3d->camera->data)->type = CAM_ORTHO;
}
if (vctrl->obtfm) {
MEM_freeN(vctrl->obtfm);
}
MEM_freeN(vctrl);
}