From e7db08056524016cc86705afd18dfd8279730069 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 14 May 2011 17:50:33 +0000 Subject: [PATCH] option to have the view controls apply to the camera view (and camera object). - follow rotate/pan/zoom/dolly operators. - auto-depth preference works. - smooth view navigation supported. - view selected, all & numpad operator work too. TODO - deal with camera transform locked axis - find a way to move/zoom the frame while the camera is locked (if it turns out to be a problem). --- release/scripts/startup/bl_ui/space_view3d.py | 3 + source/blender/editors/include/ED_view3d.h | 3 + .../editors/space_view3d/view3d_edit.c | 88 +++++++++++++++---- .../editors/space_view3d/view3d_view.c | 16 +++- source/blender/makesdna/DNA_view3d_types.h | 1 + source/blender/makesrna/intern/rna_space.c | 5 ++ 6 files changed, 99 insertions(+), 17 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 7d31bc39b0a..e6ce1d4c179 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2024,6 +2024,9 @@ class VIEW3D_PT_view3d_properties(bpy.types.Panel): elif not view.lock_object: col.prop(view, "lock_cursor", text="Lock to Cursor") + col = layout.column() + col.prop(view, "lock_camera") + col = layout.column(align=True) col.label(text="Clip:") col.prop(view, "clip_start", text="Start") diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8ed1488c599..ec1c112d42e 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -193,6 +193,9 @@ void ED_view3d_from_m4(float mat[][4], float ofs[3], float quat[4], float *dist) void ED_view3d_from_object(struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens); void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist); +void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d); +void ED_view3d_camera_lock_sync(struct View3D *v3d, struct RegionView3D *rv3d); + int view3d_is_ortho(struct View3D *v3d, struct RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 10dde714b9f..b48979188b5 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -56,6 +56,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */ #include "BIF_gl.h" @@ -80,6 +81,22 @@ /* ********************** view3d_edit: view manipulations ********************* */ +void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) +{ + if(v3d->camera && (v3d->flag2 & V3D_LOCK_CAMERA) && (rv3d->persp==RV3D_CAMOB)) { + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } +} + +void ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) +{ + if(v3d->camera && (v3d->flag2 & V3D_LOCK_CAMERA) && (rv3d->persp==RV3D_CAMOB)) { + ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + } +} + + /* ********************* box view support ***************** */ static void view3d_boxview_clip(ScrArea *sa) @@ -360,7 +377,7 @@ static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event) view3d_operator_needs_opengl(C); /* needed for zbuf drawing */ if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, vod->v3d, event->mval, vod->dyn_ofs))) { - if (rv3d->persp==RV3D_PERSP) { + if (rv3d->persp==RV3D_PERSP || (rv3d->persp==RV3D_CAMOB && (vod->v3d->flag2 & V3D_LOCK_CAMERA))) { float my_origin[3]; /* original G.vd->ofs */ float my_pivot[3]; /* view */ float dvec[3]; @@ -710,6 +727,8 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) /* avoid precision loss over time */ normalize_qt(rv3d->viewquat); + ED_view3d_camera_lock_sync(vod->v3d, rv3d); + ED_region_tag_redraw(vod->ar); } @@ -777,6 +796,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_PASS_THROUGH; } + ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); + /* switch from camera view when: */ if(rv3d->persp != RV3D_PERSP) { @@ -790,7 +811,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) ED_view3d_from_object(vod->v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } - if(rv3d->persp==RV3D_CAMOB) { + if(!(vod->v3d->flag2 & V3D_LOCK_CAMERA)) { rv3d->persp= rv3d->lpersp; } } @@ -891,7 +912,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) static void viewmove_apply(ViewOpsData *vod, int x, int y) { - if(vod->rv3d->persp==RV3D_CAMOB) { + if((vod->rv3d->persp==RV3D_CAMOB) && !(vod->v3d->flag2 & V3D_LOCK_CAMERA)) { float zoomfac= ((float)M_SQRT2 + (float)vod->rv3d->camzoom / 50.0f); zoomfac= (zoomfac * zoomfac) * 0.5f; @@ -914,6 +935,8 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) vod->oldx= x; vod->oldy= y; + ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_region_tag_redraw(vod->ar); } @@ -963,11 +986,16 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) { + ViewOpsData *vod; + /* makes op->customdata */ viewops_data_create(C, op, event); + vod= op->customdata; + + ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); + if (event->type == MOUSEPAN) { - ViewOpsData *vod= op->customdata; viewmove_apply(vod, event->prevx, event->prevy); request_depth_update(vod->rv3d); @@ -1156,6 +1184,8 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y, const short viewzoom, if(vod->rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_sync(vod->sa, vod->ar); + ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_region_tag_redraw(vod->ar); } @@ -1234,7 +1264,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) if(delta < 0) { /* this min and max is also in viewmove() */ - if(rv3d->persp==RV3D_CAMOB) { + if((rv3d->persp==RV3D_CAMOB) && !(v3d->flag2 & V3D_LOCK_CAMERA)) { rv3d->camzoom-= 10; if(rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom= RV3D_CAMZOOM_MIN; } @@ -1243,7 +1273,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) } } else { - if(rv3d->persp==RV3D_CAMOB) { + if((rv3d->persp==RV3D_CAMOB) && !(v3d->flag2 & V3D_LOCK_CAMERA)) { rv3d->camzoom+= 10; if(rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom= RV3D_CAMZOOM_MAX; } @@ -1256,6 +1286,9 @@ static int viewzoom_exec(bContext *C, wmOperator *op) view3d_boxview_sync(sa, ar); request_depth_update(rv3d); + + ED_view3d_camera_lock_sync(v3d, rv3d); + ED_region_tag_redraw(ar); viewops_data_free(C, op); @@ -1272,6 +1305,8 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event) viewops_data_create(C, op, event); vod= op->customdata; + ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); + /* if one or the other zoom position aren't set, set from event */ if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my")) { @@ -1373,6 +1408,8 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv if(vod->rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_sync(vod->sa, vod->ar); + ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_region_tag_redraw(vod->ar); } @@ -1478,6 +1515,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, wmEvent *event) vod= op->customdata; + ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); + /* if one or the other zoom position aren't set, set from event */ if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my")) { @@ -1528,10 +1567,17 @@ static int viewdolly_poll(bContext *C) { RegionView3D *rv3d= CTX_wm_region_view3d(C); - if (rv3d && rv3d->persp == RV3D_PERSP) { - return 1; + if(rv3d) { + if (rv3d->persp == RV3D_PERSP) { + return 1; + } + else { + View3D *v3d= CTX_wm_view3d(C); + if ((rv3d->persp == RV3D_CAMOB) && (v3d->flag2 & V3D_LOCK_CAMERA)) { + return 1; + } + } } - return 0; } @@ -1566,6 +1612,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in Scene *scene= CTX_data_scene(C); Base *base; float *curs; + const short skip_camera= ((rv3d->persp==RV3D_CAMOB) && (v3d->flag2 & V3D_LOCK_CAMERA)); int center= RNA_boolean_get(op->ptr, "center"); @@ -1586,6 +1633,11 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in for(base= scene->base.first; base; base= base->next) { if(BASE_VISIBLE(v3d, base)) { onedone= 1; + + if(skip_camera && base->object == v3d->camera) { + continue; + } + minmax_object(base->object, min, max); } } @@ -1621,7 +1673,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in new_dist*= size; } - if (rv3d->persp==RV3D_CAMOB) { + if ((rv3d->persp==RV3D_CAMOB) && !(v3d->flag2 & V3D_LOCK_CAMERA)) { rv3d->persp= RV3D_PERSP; smooth_view(C, v3d, ar, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL); } @@ -1665,6 +1717,7 @@ static int viewselected_exec(bContext *C, wmOperator *UNUSED(op)) /* like a loca Object *obedit= CTX_data_edit_object(C); float size, min[3], max[3], afm[3]; int ok=0, ok_dist=1; + const short skip_camera= ((rv3d->persp==RV3D_CAMOB) && (v3d->flag2 & V3D_LOCK_CAMERA)); /* SMOOTHVIEW */ float new_ofs[3]; @@ -1718,17 +1771,20 @@ static int viewselected_exec(bContext *C, wmOperator *UNUSED(op)) /* like a loca ok= PE_minmax(scene, min, max); } else { - Base *base= FIRSTBASE; - while(base) { + Base *base; + for(base= FIRSTBASE; base; base = base->next) { if(TESTBASE(v3d, base)) { + if(skip_camera && base->object == v3d->camera) { + continue; + } + /* account for duplis */ if (minmax_object_duplis(scene, base->object, min, max)==0) minmax_object(base->object, min, max); /* use if duplis not found */ ok= 1; } - base= base->next; } } @@ -1764,7 +1820,7 @@ static int viewselected_exec(bContext *C, wmOperator *UNUSED(op)) /* like a loca new_dist*= size; } - if (rv3d->persp==RV3D_CAMOB) { + if (rv3d->persp==RV3D_CAMOB && !(v3d->flag2 & V3D_LOCK_CAMERA)) { rv3d->persp= RV3D_PERSP; smooth_view(C, v3d, ar, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL); } @@ -2355,6 +2411,7 @@ static EnumPropertyItem prop_view_orbit_items[] = { static int vieworbit_exec(bContext *C, wmOperator *op) { + View3D *v3d= CTX_wm_view3d(C); ARegion *ar= ED_view3d_context_region_unlock(C); RegionView3D *rv3d= ar->regiondata; /* no NULL check is needed, poll checks */ float phi, q1[4], new_quat[4]; @@ -2363,8 +2420,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op) orbitdir = RNA_enum_get(op->ptr, "type"); if(rv3d->viewlock==0) { - - if(rv3d->persp != RV3D_CAMOB) { + if((rv3d->persp != RV3D_CAMOB) || (v3d->flag2 & V3D_LOCK_CAMERA)) { if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) { float si; /* z-axis */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5c54c32236b..82945b425cf 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -161,7 +161,19 @@ void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Objec sms.new_dist= rv3d->dist; sms.new_lens= v3d->lens; sms.to_camera= 0; - + + /* note on camera locking, this is a little confusing but works ok. + * we may be changing the view 'as if' there is no active camera, but infact + * there is an active camera which is locked to the view. + * + * In the case where smooth view is moving _to_ a camera we dont want that + * camera to be moved or changed, so only when the camera is not being set should + * we allow camera option locking to initialize the view settings from the camera. + */ + if(camera == NULL && oldcamera == NULL) { + ED_view3d_camera_lock_init(v3d, rv3d); + } + /* store the options we want to end with */ if(ofs) copy_v3_v3(sms.new_ofs, ofs); if(quat) copy_qt_qt(sms.new_quat, quat); @@ -325,6 +337,8 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv; v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv; + + ED_view3d_camera_lock_sync(v3d, rv3d); } if(rv3d->viewlock & RV3D_BOXVIEW) diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index c9a440522d1..e76cd4b07d6 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -244,6 +244,7 @@ typedef struct View3D { #define V3D_RENDER_OVERRIDE 4 #define V3D_SOLID_TEX 8 #define V3D_DISPGP 16 +#define V3D_LOCK_CAMERA 32 /* View3D->around */ #define V3D_CENTER 0 diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index c92c0d971e8..eeb370854fc 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1298,6 +1298,11 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Textured Solid", "Display face-assigned textures in solid view"); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); + prop= RNA_def_property(srna, "lock_camera", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_LOCK_CAMERA); + RNA_def_property_ui_text(prop, "Lock Camera to View", "Enable view navigation within the camera view"); + RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); + prop= RNA_def_property(srna, "show_only_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE); RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered");