View Dolly Operator: Ctrl+Shift+MMB.
authorCampbell Barton <ideasman42@gmail.com>
Fri, 22 Apr 2011 15:34:07 +0000 (15:34 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 22 Apr 2011 15:34:07 +0000 (15:34 +0000)
Recently there were 2 reports about zoom not working right because at some point you can't zoom in any further.

This is not actually a bug with zoom but a limitation in blender that there is no way to move the viewpoint forward (unless you count rotate 90d, pan, rotate back which is a crummy workaround).

So adding view dolly operator:
- Supports zoom to mouse position setting.
- Supports dolly hoz/vert, invert setting.
- Moves by a fraction of the view 'dist', so the zoom distance my be roughly in proportion to the scale of objects in the scene.

only used in perspective view since this is not useful in camera/ortho view.

source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_ops.c

index 2b971a84af62baa2b47c8d7c2eeb30318bbeef94..b377bb20baab7d889fee8341a3797c0c561d0fef 100644 (file)
@@ -285,6 +285,7 @@ typedef struct ViewOpsData {
 
        float oldquat[4];
        float trackvec[3];
+       float mousevec[3]; /* dolly only */
        float reverse, dist0;
        float grid, far;
        short axis_snap; /* view rotate only */
@@ -346,9 +347,9 @@ static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
        vod->origy= vod->oldy= event->y;
        vod->origkey= event->type; /* the key that triggered the operator.  */
        vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
+       copy_v3_v3(vod->ofs, rv3d->ofs);
 
        if (vod->use_dyn_ofs) {
-               copy_v3_v3(vod->ofs, rv3d->ofs);
                /* If there's no selection, lastofs is unmodified and last value since static */
                calculateTransformCenter(C, V3D_CENTROID, lastofs);
                negate_v3_v3(vod->dyn_ofs, lastofs);
@@ -394,6 +395,9 @@ static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
                }
        }
 
+       /* for dolly */
+       window_to_3d_vector(vod->ar, vod->mousevec, (vod->oldx - vod->ar->winrct.xmin)-(vod->ar->winx)/2, (vod->oldy - vod->ar->winrct.ymin)-(vod->ar->winy)/2);
+
        /* lookup, we dont pass on v3d to prevent confusement */
        vod->grid= v3d->grid;
        vod->far= v3d->far;
@@ -1262,6 +1266,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
+/* viewdolly_invoke() copied this function, changes here may apply there */
 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        /* if one or the other zoom position aren't set, set from event */
@@ -1339,6 +1344,232 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
        RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
 }
 
+
+/* ************************ viewdolly ******************************** */
+static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
+{
+       RegionView3D *rv3d= ar->regiondata;
+       madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, 1.0 - dfac);
+}
+
+static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_invert)
+{
+       float zfac=1.0;
+
+       {
+               float len1, len2;
+
+               if (U.uiflag & USER_ZOOM_HORIZ) {
+                       len1 = (vod->ar->winrct.xmax - x) + 5;
+                       len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+               }
+               else {
+                       len1 = (vod->ar->winrct.ymax - y) + 5;
+                       len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
+               }
+               if (zoom_invert)
+                       SWAP(float, len1, len2);
+
+               zfac =  1.0 + ((len2 - len1) * 0.01 * vod->rv3d->dist);
+       }
+
+       if(zfac != 1.0f)
+               view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac);
+
+       if(vod->rv3d->viewlock & RV3D_BOXVIEW)
+               view3d_boxview_sync(vod->sa, vod->ar);
+
+       ED_region_tag_redraw(vod->ar);
+}
+
+
+static int viewdolly_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ViewOpsData *vod= op->customdata;
+       short event_code= VIEW_PASS;
+
+       /* execute the events */
+       if(event->type==MOUSEMOVE) {
+               event_code= VIEW_APPLY;
+       }
+       else if(event->type==EVT_MODAL_MAP) {
+               switch (event->val) {
+                       case VIEW_MODAL_CONFIRM:
+                               event_code= VIEW_CONFIRM;
+                               break;
+                       case VIEWROT_MODAL_SWITCH_MOVE:
+                               WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
+                       case VIEWROT_MODAL_SWITCH_ROTATE:
+                               WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
+               }
+       }
+       else if(event->type==vod->origkey && event->val==KM_RELEASE) {
+               event_code= VIEW_CONFIRM;
+       }
+
+       if(event_code==VIEW_APPLY) {
+               viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0);
+       }
+       else if (event_code==VIEW_CONFIRM) {
+               request_depth_update(vod->rv3d);
+               viewops_data_free(C, op);
+
+               return OPERATOR_FINISHED;
+       }
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int viewdolly_exec(bContext *C, wmOperator *op)
+{
+       View3D *v3d;
+       RegionView3D *rv3d;
+       ScrArea *sa;
+       ARegion *ar;
+       float mousevec[3];
+
+       int delta= RNA_int_get(op->ptr, "delta");
+       int mx, my;
+
+       if(op->customdata) {
+               ViewOpsData *vod= op->customdata;
+
+               sa= vod->sa;
+               ar= vod->ar;
+               copy_v3_v3(mousevec, vod->mousevec);
+       }
+       else {
+               sa= CTX_wm_area(C);
+               ar= CTX_wm_region(C);
+               normalize_v3_v3(mousevec, ((RegionView3D *)ar->regiondata)->viewinv[2]);
+       }
+
+       v3d= sa->spacedata.first;
+       rv3d= ar->regiondata;
+
+       /* overwrite the mouse vector with the view direction (zoom into the center) */
+       if((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) {
+               normalize_v3_v3(mousevec, rv3d->viewinv[2]);
+       }
+
+       mx= RNA_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2;
+       my= RNA_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2;
+
+
+
+       if(delta < 0) {
+               view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.2f);
+       }
+       else {
+               view_dolly_mouseloc(ar, rv3d->ofs, mousevec, .83333f);
+       }
+
+       if(rv3d->viewlock & RV3D_BOXVIEW)
+               view3d_boxview_sync(sa, ar);
+
+       request_depth_update(rv3d);
+       ED_region_tag_redraw(ar);
+
+       viewops_data_free(C, op);
+
+       return OPERATOR_FINISHED;
+}
+
+/* copied from viewzoom_invoke(), changes here may apply there */
+static int viewdolly_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{      
+       /* 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"))
+       {
+               RNA_int_set(op->ptr, "mx", event->x);
+               RNA_int_set(op->ptr, "my", event->y);
+       }
+
+       if(RNA_property_is_set(op->ptr, "delta")) {
+               /* makes op->customdata */
+               viewops_data_create(C, op, event);
+               viewdolly_exec(C, op);
+       }
+       else {
+               ViewOpsData *vod;
+
+               /* makes op->customdata */
+               viewops_data_create(C, op, event);
+
+               vod= op->customdata;
+
+               /* overwrite the mouse vector with the view direction (zoom into the center) */
+               if((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) {
+                       normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]);
+               }
+
+               if (event->type == MOUSEZOOM) {
+                       /* Bypass Zoom invert flag for track pads (pass FALSE always) */
+
+                       if (U.uiflag & USER_ZOOM_HORIZ) {
+                               vod->origx = vod->oldx = event->x;
+                               viewdolly_apply(vod, event->prevx, event->prevy, FALSE);
+                       }
+                       else {
+
+                               /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
+                               vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
+                               viewdolly_apply(vod, event->prevx, event->prevy, FALSE);
+                       }
+                       request_depth_update(vod->rv3d);
+
+                       viewops_data_free(C, op);
+                       return OPERATOR_FINISHED;
+               }
+               else {
+                       /* add temp handler */
+                       WM_event_add_modal_handler(C, op);
+
+                       return OPERATOR_RUNNING_MODAL;
+               }
+       }
+       return OPERATOR_FINISHED;
+}
+
+/* like ED_operator_region_view3d_active but check its not in ortho view */
+static int viewdolly_poll(bContext *C)
+{
+       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+
+       if (rv3d && rv3d->persp == RV3D_PERSP) {
+               return 1;
+       }
+
+       return 0;
+}
+
+void VIEW3D_OT_dolly(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Dolly view";
+       ot->description = "Dolly in/out in the view";
+       ot->idname= "VIEW3D_OT_dolly";
+
+       /* api callbacks */
+       ot->invoke= viewdolly_invoke;
+       ot->exec= viewdolly_exec;
+       ot->modal= viewdolly_modal;
+       ot->poll= viewdolly_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
+
+       RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
+       RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
+}
+
+
+
 static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
 {
        ARegion *ar= CTX_wm_region(C);
index d66a3b99911ead14a1f6031ad28d288cc4dc0a57..12ad01e3977c9a11f8511256d6ab6416d7d59bb0 100644 (file)
@@ -68,6 +68,7 @@ void view3d_operatortypes(void);
 
 /* view3d_edit.c */
 void VIEW3D_OT_zoom(struct wmOperatorType *ot);
+void VIEW3D_OT_dolly(struct wmOperatorType *ot);
 void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
 void VIEW3D_OT_move(struct wmOperatorType *ot);
 void VIEW3D_OT_rotate(struct wmOperatorType *ot);
index 30ca1638d3449b57b623f612372d039d4b078dc6..4942030c51638bcee0809c536f99b6fd173c387c 100644 (file)
@@ -63,6 +63,7 @@ void view3d_operatortypes(void)
        WM_operatortype_append(VIEW3D_OT_move);
        WM_operatortype_append(VIEW3D_OT_zoom);
        WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
+       WM_operatortype_append(VIEW3D_OT_dolly);
        WM_operatortype_append(VIEW3D_OT_view_all);
        WM_operatortype_append(VIEW3D_OT_viewnumpad);
        WM_operatortype_append(VIEW3D_OT_view_orbit);
@@ -129,6 +130,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
        WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0);
        WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_verify_item(keymap, "VIEW3D_OT_dolly", MIDDLEMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
        WM_keymap_verify_item(keymap, "VIEW3D_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
        WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center_cursor", PADPERIOD, KM_PRESS, KM_CTRL, 0);