option to have the view controls apply to the camera view (and camera object).
authorCampbell Barton <ideasman42@gmail.com>
Sat, 14 May 2011 17:50:33 +0000 (17:50 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 14 May 2011 17:50:33 +0000 (17:50 +0000)
- 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
source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_space.c

index 7d31bc39b0a96f8b809987e583b17986ce5dfef7..e6ce1d4c1791d30d3aea140bcf55836308951d9c 100644 (file)
@@ -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")
index 8ed1488c599d860826a46a10f48dbbc31412b857..ec1c112d42ed39d98f965f1d0843f17079b66dfa 100644 (file)
@@ -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);
 
 
index 10dde714b9f681f2c222a58791abd451cedb4cf7..b48979188b5d4669dccc2a17f3f38bb247dc4e5a 100644 (file)
@@ -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"
 
 /* ********************** 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 */
index 5c54c32236b7483cc370aa9dc14cfe41258f418a..82945b425cfaa0d18823ef6b690c6d36e2159c4f 100644 (file)
@@ -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)
index c9a440522d1cce441be0f6d80b0b7aa492fb257c..e76cd4b07d6e6c9c5115d8446e50bf76eed9d1f5 100644 (file)
@@ -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
index c92c0d971e81fa84040a5ba1289ae26d95908f31..eeb370854fcea935bb54d26174b611514bd36cb8 100644 (file)
@@ -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");