commit b5eee2228867aea8af4a3f5b8c7be21f6db94687
Author: Campbell Barton <campbell@blender.org>
Date: Sat Aug 6 19:31:47 2022 +1000
Experiment supporting undo for smooth view operations (apply on 8f915f0efba3da652ad06fa9fcfba7d6ca26e719).
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index c16e5ce5655..1cc2cdff5b3 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1414,7 +1414,6 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
rv3d->render_engine = NULL;
rv3d->sms = NULL;
- rv3d->smooth_timer = NULL;
rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING);
rv3d->runtime_viewlock = 0;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index a423a842019..38ae2134fbd 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1025,7 +1025,6 @@ static void *view3d_main_region_duplicate(void *poin)
new->render_engine = NULL;
new->sms = NULL;
- new->smooth_timer = NULL;
return new;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c
index 88e004aac48..cd33682f216 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_navigate.c
@@ -495,6 +495,8 @@ static void axis_set_view(bContext *C,
.camera_old = v3d->camera,
.ofs = rv3d->ofs,
.quat = quat,
+ /* No undo because this switches to/from camera. */
+ .undo = {NULL},
});
}
else if (orig_persp == RV3D_CAMOB && v3d->camera) {
@@ -518,6 +520,8 @@ static void axis_set_view(bContext *C,
.ofs = ofs,
.quat = quat,
.dist = &dist,
+ /* No undo because this switches to/from camera. */
+ .undo = {NULL},
});
}
else {
@@ -540,6 +544,8 @@ static void axis_set_view(bContext *C,
&(const V3D_SmoothParams){
.quat = quat,
.dyn_ofs = dyn_ofs_pt,
+ /* No undo because this isn't a camera view. */
+ .undo = {NULL},
});
}
}
@@ -694,6 +700,7 @@ static void view3d_from_minmax(bContext *C,
.camera_old = v3d->camera,
.ofs = new_ofs,
.dist = ok_dist ? &new_dist : NULL,
+ .undo = {.str = "View All"},
});
}
else {
@@ -704,6 +711,7 @@ static void view3d_from_minmax(bContext *C,
&(const V3D_SmoothParams){
.ofs = new_ofs,
.dist = ok_dist ? &new_dist : NULL,
+ .undo = {.str = "View All"},
});
}
@@ -803,6 +811,12 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
ED_view3d_clipping_clamp_minmax(rv3d, min, max);
}
+ const V3D_SmoothParams_Undo undo = {
+ .str = op->type->name,
+ .grouped = false,
+ };
+ ED_view3d_smooth_view_undo_begin(C, v3d, &undo);
+
if (use_all_regions) {
view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx);
}
@@ -810,6 +824,8 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx);
}
+ ED_view3d_smooth_view_undo_end(C, v3d);
+
return OPERATOR_FINISHED;
}
@@ -1020,8 +1036,14 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
/* non camera center */
float new_ofs[3];
negate_v3_v3(new_ofs, scene->cursor.location);
- ED_view3d_smooth_view(
- C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
+ ED_view3d_smooth_view(C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .ofs = new_ofs,
+ .undo = {.str = op->type->name},
+ });
/* Smooth view does view-lock #RV3D_BOXVIEW copy. */
}
@@ -1074,8 +1096,14 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_view3d_win_to_3d_int(v3d, region, new_ofs, event->mval, new_ofs);
}
negate_v3(new_ofs);
- ED_view3d_smooth_view(
- C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
+ ED_view3d_smooth_view(C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .ofs = new_ofs,
+ .undo = {.str = op->type->name},
+ });
}
return OPERATOR_FINISHED;
@@ -1277,7 +1305,7 @@ static int view_camera_exec(bContext *C, wmOperator *op)
if (rv3d->persp != RV3D_CAMOB) {
Object *ob = OBACT(view_layer);
- if (!rv3d->smooth_timer) {
+ if (!v3d->runtime.smooth_timer) {
/* store settings of current view before allowing overwriting with camera view
* only if we're not currently in a view transition */
@@ -1318,17 +1346,20 @@ static int view_camera_exec(bContext *C, wmOperator *op)
/* finally do snazzy view zooming */
rv3d->persp = RV3D_CAMOB;
- ED_view3d_smooth_view(C,
- v3d,
- region,
- smooth_viewtx,
- &(const V3D_SmoothParams){
- .camera = v3d->camera,
- .ofs = rv3d->ofs,
- .quat = rv3d->viewquat,
- .dist = &rv3d->dist,
- .lens = &v3d->lens,
- });
+ ED_view3d_smooth_view(
+ C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .camera = v3d->camera,
+ .ofs = rv3d->ofs,
+ .quat = rv3d->viewquat,
+ .dist = &rv3d->dist,
+ .lens = &v3d->lens,
+ /* No undo because this changes cameras (and wont move the camera). */
+ .undo = {NULL},
+ });
}
else {
/* return to settings of last view */
@@ -1475,6 +1506,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.quat = quat_new,
.dyn_ofs = dyn_ofs_pt,
+ /* Group as successive orbit may run by holding a key. */
+ .undo = {.str = op->type->name, .grouped = true},
});
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_navigate.h b/source/blender/editors/space_view3d/view3d_navigate.h
index fc7bc11295a..63afa96c437 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.h
+++ b/source/blender/editors/space_view3d/view3d_navigate.h
@@ -220,6 +220,20 @@ void VIEW3D_OT_rotate(struct wmOperatorType *ot);
/* view3d_navigate_smoothview.c */
+/** Optionally perform an undo push when the smooth-view operation is finished. */
+typedef struct V3D_SmoothParams_Undo {
+ /**
+ * When set, finishing the smooth-view operation may perform an undo-push
+ * (in the case it's transforming a camera which is locked to the view).
+ */
+ const char *str;
+ /**
+ * When set, use grouped undo pushes.
+ * use for operations that are likely to run by holding a key or mouse-wheel.
+ */
+ bool grouped;
+} V3D_SmoothParams_Undo;
+
/**
* Parameters for setting the new 3D Viewport state.
*
@@ -231,12 +245,14 @@ typedef struct V3D_SmoothParams {
/** Alternate rotation center, when set `ofs` must be NULL. */
const float *dyn_ofs;
+
+ V3D_SmoothParams_Undo undo;
} V3D_SmoothParams;
/**
* The arguments are the desired situation.
*/
-void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
+bool ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
struct ScrArea *area,
@@ -245,7 +261,7 @@ void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
int smooth_viewtx,
const V3D_SmoothParams *sview);
-void ED_view3d_smooth_view(struct bContext *C,
+bool ED_view3d_smooth_view(struct bContext *C,
struct View3D *v3d,
struct ARegion *region,
int smooth_viewtx,
@@ -261,6 +277,11 @@ void ED_view3d_smooth_view_force_finish(struct bContext *C,
void VIEW3D_OT_smoothview(struct wmOperatorType *ot);
+void ED_view3d_smooth_view_undo_begin(struct bContext *C,
+ struct View3D *v3d,
+ const V3D_SmoothParams_Undo *undo);
+void ED_view3d_smooth_view_undo_end(struct bContext *C, struct View3D *v3d);
+
/* view3d_navigate_walk.c */
void walk_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_navigate_roll.c b/source/blender/editors/space_view3d/view3d_navigate_roll.c
index 087ca72211e..c32a22bc2ea 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_roll.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_roll.c
@@ -202,6 +202,8 @@ static int viewroll_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.quat = quat_new,
.dyn_ofs = dyn_ofs_pt,
+ /* Group as successive roll may run by holding a key. */
+ .undo = {.str = op->type->name, .grouped = true},
});
viewops_data_free(C, op->customdata);
diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
index 48af126d8a9..c2c8fc9f1da 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
@@ -8,6 +8,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -21,6 +22,68 @@
#include "view3d_intern.h"
#include "view3d_navigate.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Smooth View Undo
+ * \{ */
+
+struct SmoothViewUndo {
+ V3D_SmoothParams_Undo undo;
+ LinkNode *region_undo;
+};
+
+static void xxx_destroy(View3D *v3d);
+
+static void xxx_create(View3D *v3d, const V3D_SmoothParams_Undo *undo)
+{
+ xxx_destroy(v3d);
+ struct SmoothViewUndo *x = MEM_callocN(sizeof(struct SmoothViewUndo), __func__);
+ x->undo = *undo;
+ v3d->runtime.smooth_undo = x;
+}
+
+static void xxx_destroy(View3D *v3d)
+{
+ struct SmoothViewUndo *x = v3d->runtime.smooth_undo;
+ BLI_linklist_free(x->region_undo, NULL);
+ MEM_SAFE_FREE(v3d->runtime.smooth_undo);
+}
+
+static void xxx_push_region(View3D *v3d, ARegion *region)
+{
+ BLI_assert(v3d->runtime.smooth_undo);
+ struct SmoothViewUndo *x = v3d->runtime.smooth_undo;
+ BLI_linklist_prepend(&x->region_undo, region);
+}
+
+void ED_view3d_smooth_view_undo_begin(bContext *UNUSED(C),
+ View3D *v3d,
+ const V3D_SmoothParams_Undo *undo)
+{
+ xxx_create(v3d, undo);
+}
+
+void ED_view3d_smooth_view_undo_end(bContext *C, View3D *v3d)
+{
+ BLI_assert(v3d->runtime.smooth_undo);
+
+ struct SmoothViewUndo *x = v3d->runtime.smooth_undo;
+ for (LinkNode *node = x->region_undo; node; node = node->next) {
+ ARegion *region = node->link;
+ RegionView3D *rv3d = region->regiondata;
+ const bool undo_pushed = x->undo.grouped ?
+ ED_view3d_camera_lock_undo_grouped_push(
+ x->undo.str, v3d, rv3d, C) :
+ ED_view3d_camera_lock_undo_push(x->undo.str, v3d, rv3d, C);
+
+ if (undo_pushed) {
+ break;
+ }
+ }
+ xxx_destroy(v3d);
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Smooth View Operator & Utilities
*
@@ -75,7 +138,7 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
}
/* will start timer if appropriate */
-void ED_view3d_smooth_view_ex(
+bool ED_view3d_smooth_view_ex(
/* avoid passing in the context */
const Depsgraph *depsgraph,
wmWindowManager *wm,
@@ -157,9 +220,11 @@ void ED_view3d_smooth_view_ex(
equals_v4v4(sms.dst.quat, rv3d->viewquat) /* Rotation. */
) {
/* Early return if nothing changed. */
- return;
+ return true;
}
+ bool finished = false;
+
/* Skip smooth viewing for external render engine draw. */
if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
@@ -211,11 +276,12 @@ void ED_view3d_smooth_view_ex(
rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
}
*rv3d->sms = sms;
- if (rv3d->smooth_timer) {
- WM_event_remove_timer(wm, win, rv3d->smooth_timer);
+
+ if (v3d->runtime.smooth_timer) {
+ WM_event_remove_timer(wm, win, v3d->runtime.smooth_timer);
}
/* #TIMER1 is hard-coded in key-map. */
- rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
+ v3d->runtime.smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
}
else {
/* Animation is disabled, apply immediately. */
@@ -235,10 +301,13 @@ void ED_view3d_smooth_view_ex(
ED_region_tag_redraw(region);
WM_event_add_mousemove(win);
+ finished = true;
}
+
+ return finished;
}
-void ED_view3d_smooth_view(bContext *C,
+bool ED_view3d_smooth_view(bContext *C,
View3D *v3d,
ARegion *region,
const int smooth_viewtx,
@@ -248,8 +317,52 @@ void ED_view3d_smooth_view(bContext *C,
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
+ /* Make a copy that doesn't use undo since #ED_view3d_smooth_view_ex doesn't support undo
+ * and will assert if this is passed in. */
+ struct V3D_SmoothParams sview_copy = *sview;
+ bool handle_undo = (!v3d->runtime.smooth_undo && sview->undo.str);
+ if (handle_undo) {
+ ED_view3d_smooth_view_undo_begin(C, v3d, &sview->undo);
+ }
+ sview_copy.undo.str = NULL;
+
+ const bool finished = ED_view3d_smooth_view_ex(
+ depsgraph, wm, win, area, v3d, region, smooth_viewtx, &sview_copy);
+
+ if (handle_undo) {
+ ED_view3d_smooth_view_undo_end(C, v3d);
+ }
+ return finished;
+}
+
+/** Remove `View3D.runtime.smooth_timer` unless another region is using it. */
+static void view3d_smoothview_clear_unused_timer(wmWindowManager *wm,
+ wmWindow *win,
+ View3D *v3d,
+ ARegion *region)
+{
+ if (!v3d->runtime.smooth_timer) {
+ return;
+ }
- ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview);
+ /* Passing in the area would be more convenient, but the caller doesn't have access to it. */
+ while (region->prev) {
+ region = region->prev;
+ }
+ for (; region; region = region->next) {
+ if (region->type != RGN_TYPE_WINDOW) {
+ continue;
+ }
+ const RegionView3D *rv3d = region->regiondata;
+ if (rv3d->sms) {
+ break;
+ }
+ }
+ if (!region) {
+ return; /* A region has smooth-view data, exit. */
+ }
+
+ WM_event_remove_timer(wm, win, v3d->runtime.smooth_timer);
}
/* only meant for timer usage */
@@ -261,7 +374,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
float step, step_inv;
if (sms->time_allowed != 0.0) {
- step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
+ step = (float)((v3d->runtime.smooth_timer->duration) / sms->time_allowed);
}
else {
step = 1.0f;
@@ -283,6 +396,9 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
+ if (v3d->runtime.smooth_undo) {
+ xxx_push_region(v3d, region);
+ }
}
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
@@ -292,8 +408,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
MEM_freeN(rv3d->sms);
rv3d->sms = NULL;
- WM_event_remove_timer(wm, win, rv3d->smooth_timer);
- rv3d->smooth_timer = NULL;
+ view3d_smoothview_clear_unused_timer(wm, win, v3d, region);
rv3d->rflag &= ~RV3D_NAVIGATING;
/* Event handling won't know if a UI item has been moved under the pointer. */
@@ -342,36 +457,65 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
}
}
+static void view3d_smoothview_apply_all_regions_with_undo(
+ bContext *C, View3D *v3d, ARegion *region, bool sync_boxview, bool force)
+{
+ bool handle_undo = v3d->runtime.smooth_undo == NULL;
+ if (handle_undo) {
+ const V3D_SmoothParams_Undo undo = {.str = "Smooth View", .grouped = false};
+ ED_view3d_smooth_view_undo_begin(C, v3d, &undo);
+ }
+
+ /* Passing in the area would be more convenient, but the caller doesn't have access to it. */
+ while (region->prev) {
+ region = region->prev;
+ }
+ for (; region; region = region->next) {
+ if (region->regiontype != RGN_TYPE_WINDOW) {
+ continue;
+ }
+ const RegionView3D *rv3d = region->regiondata;
+ if (!rv3d->sms) {
+ continue;
+ }
+ if (force) {
+ rv3d->sms->time_allowed = 0.0; /* force finishing */
+ }
+
+ view3d_smoothview_apply(C, v3d, region, sync_boxview);
+
+ /* Force update of view matrix so tools that run immediately after
+ * can use them without redrawing first. */
+ if (force) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ED_view3d_update_viewmat(depsgraph, scene, v3d, region, NULL, NULL, NULL, false);
+ }
+ }
+
+ if (handle_undo) {
+ ED_view3d_smooth_view_undo_end(C, v3d);
+ }
+}
+
static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = region->regiondata;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
/* escape if not our timer */
- if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) {
+ if (v3d->runtime.smooth_timer == NULL || v3d->runtime.smooth_timer != event->customdata) {
return OPERATOR_PASS_THROUGH;
}
- view3d_smoothview_apply(C, v3d, region, true);
+ view3d_smoothview_apply_all_regions_with_undo(C, v3d, area->regionbase.first, true, false);
return OPERATOR_FINISHED;
}
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
{
- RegionView3D *rv3d = region->regiondata;
-
- if (rv3d && rv3d->sms) {
- rv3d->sms->time_allowed = 0.0; /* force finishing */
- view3d_smoothview_apply(C, v3d, region, false);
-
- /* force update of view matrix so tools that run immediately after
- * can use them without redrawing first */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ED_view3d_update_viewmat(depsgraph, scene, v3d, region, NULL, NULL, NULL, false);
- }
+ view3d_smoothview_apply_all_regions_with_undo(C, v3d, region, false, true);
}
void VIEW3D_OT_smoothview(wmOperatorType *ot)
diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
index f834efe4a7b..616f1cd9c37 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
@@ -173,6 +173,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.ofs = new_ofs,
.dist = &new_dist,
+ .undo = {.str = op->type->name},
});
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index fc88737ca70..8f28699f94f 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -202,6 +202,8 @@ static void sync_viewport_camera_smoothview(bContext *C,
.quat = other_rv3d->viewquat,
.dist = &other_rv3d->dist,
.lens = &other_v3d->lens,
+ /* No undo because this switches cameras. */
+ .undo = {NULL},
});
}
else {
@@ -256,6 +258,8 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
.quat = rv3d->viewquat,
.dist = &rv3d->dist,
.lens = &v3d->lens,
+ /* No undo because this switches cameras. */
+ .undo = {NULL},
});
}
@@ -939,6 +943,8 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
.quat = rv3d->viewquat,
.dist = ok_dist ? &dist_new : NULL,
.lens = &v3d->lens,
+ /* No undo because this doesn't move the camera. */
+ .undo = {NULL},
});
}
}
@@ -1008,6 +1014,8 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
.ofs = rv3d->localvd->ofs,
.quat = rv3d->localvd->viewquat,
.dist = &rv3d->localvd->dist,
+ /* No undo because this doesn't move the camera. */
+ .undo = {NULL},
});
}
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 8554d070dc3..8d232d69b68 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -61,7 +61,6 @@ typedef struct RegionView3D {
/** Animated smooth view. */
struct SmoothView3DStore *sms;
- struct wmTimer *smooth_timer;
/** Transform gizmo matrix. */
float twmat[4][4];
@@ -250,6 +249,10 @@ typedef struct View3D_Runtime {
char _pad1[4];
/* Only used for overlay stats while in local-view. */
struct SceneStats *local_stats;
+
+ /** Animated smooth view timer. */
+ struct wmTimer *smooth_timer;
+ void *smooth_undo;
} View3D_Runtime;
/** 3D ViewPort Struct. */