[PATCH 4/4] Implement animated zoom transitions.

Scott Moreau oreaus at gmail.com
Mon May 21 11:42:53 PDT 2012


---
 src/compositor.c |  206 ++++++++++++++++++++++++++++++++++++++++++++++++------
 src/compositor.h |   45 ++++++++----
 src/shell.c      |   14 +---
 src/util.c       |    7 +-
 4 files changed, 222 insertions(+), 50 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index b0b0f75..1e0ed84 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2439,6 +2439,126 @@ weston_output_destroy(struct weston_output *output)
 	wl_display_remove_global(c->wl_display, output->global);
 }
 
+static void
+weston_zoom_frame_xy(struct weston_animation *animation,
+		struct weston_output *output, uint32_t msecs)
+{
+	if (!output->zoom.animation.moving)
+		return;
+
+	weston_spring_update(&output->zoom.spring.x, msecs);
+	weston_spring_update(&output->zoom.spring.y, msecs);
+
+	if (output->zoom.spring.x.current < output->zoom.trans_min) {
+		output->zoom.spring.x.current = output->zoom.trans_min;
+		output->zoom.spring.x.target = output->zoom.trans_min;
+	}
+	if (output->zoom.spring.x.current > output->zoom.trans_max) {
+		output->zoom.spring.x.current = output->zoom.trans_max;
+		output->zoom.spring.x.target = output->zoom.trans_max;
+	}
+	if (output->zoom.spring.y.current < output->zoom.trans_min) {
+		output->zoom.spring.y.current = output->zoom.trans_min;
+		output->zoom.spring.y.target = output->zoom.trans_min;
+	}
+	if (output->zoom.spring.y.current > output->zoom.trans_max) {
+		output->zoom.spring.y.current = output->zoom.trans_max;
+		output->zoom.spring.y.target = output->zoom.trans_max;
+	}
+
+	if (weston_spring_done(&output->zoom.spring.x))
+		output->zoom.spring.x.current = output->zoom.trans_x;
+
+	if (weston_spring_done(&output->zoom.spring.y))
+		output->zoom.spring.y.current = output->zoom.trans_y;
+
+	if (weston_spring_done(&output->zoom.spring.x) ||
+	    weston_spring_done(&output->zoom.spring.y)) {
+		wl_list_remove(&output->zoom.animation.xy.link);
+		output->zoom.animation.moving = 0;
+	} else {
+		output->dirty = 1;
+		weston_output_damage(output);
+	}
+}
+
+static void
+weston_zoom_frame_z(struct weston_animation *animation,
+		struct weston_output *output, uint32_t msecs)
+{
+	if (!output->zoom.animation.zooming)
+		return;
+
+	weston_spring_update(&output->zoom.spring.z, msecs);
+
+	if (output->zoom.spring.z.current < 0.0) {
+		output->zoom.spring.z.current = 0.0;
+		output->zoom.spring.z.target = 0.0;
+	}
+
+	if (output->zoom.spring.z.current > output->zoom.maximum_level) {
+		output->zoom.spring.z.current = output->zoom.maximum_level;
+		output->zoom.spring.z.target = output->zoom.maximum_level;
+	}
+
+	if (weston_spring_done(&output->zoom.spring.z)) {
+		output->zoom.animation.from_level = output->zoom.level;
+		output->zoom.spring.z.current = output->zoom.level;
+		wl_list_remove(&output->zoom.animation.z.link);
+		wl_list_init(&output->zoom.animation.z.link);
+		output->zoom.animation.zooming = 0;
+		if (output->zoom.level <= 0.0)
+			output->zoom.active = 0;
+	} else {
+		output->dirty = 1;
+		weston_output_damage(output);
+	}
+}
+
+static void
+weston_zoom_transition(struct weston_output *output, int xy_transition)
+{
+	if (!output->zoom.animation.moving && xy_transition) {
+		if (output->zoom.animation.from_x != output->zoom.trans_x)
+			weston_spring_init(&output->zoom.spring.x, 250.0,
+						output->zoom.animation.from_x,
+						output->zoom.trans_x);
+		if (output->zoom.animation.from_y != output->zoom.trans_y)
+			weston_spring_init(&output->zoom.spring.y, 250.0,
+						output->zoom.animation.from_y,
+						output->zoom.trans_y);
+		output->zoom.spring.x.friction = 1000;
+		output->zoom.spring.y.friction = 1000;
+
+		output->zoom.spring.x.timestamp = weston_compositor_get_time();
+		output->zoom.spring.y.timestamp = output->zoom.spring.x.timestamp;
+
+		wl_list_insert(&output->compositor->animation_list,
+			       &output->zoom.animation.xy.link);
+
+		output->zoom.animation.moving = 1;
+	}
+
+	if (!output->zoom.animation.zooming &&
+			output->zoom.animation.from_level != output->zoom.level) {
+		weston_spring_init(&output->zoom.spring.z, 250.0,
+					output->zoom.animation.from_level,
+					output->zoom.level);
+		output->zoom.spring.z.friction = 1000;
+		output->zoom.animation.from_level = output->zoom.level;
+		output->zoom.spring.z.timestamp = weston_compositor_get_time();
+		wl_list_insert(output->compositor->animation_list.prev,
+			       &output->zoom.animation.z.link);
+		output->zoom.animation.zooming = 1;
+	}
+
+	output->zoom.animation.from_x = output->zoom.trans_x;
+	output->zoom.animation.from_y = output->zoom.trans_y;
+
+	output->dirty = 1;
+	weston_output_damage(output);
+}
+
 WL_EXPORT void
 weston_text_cursor_position_notify(struct weston_surface *surface,
 						int32_t x, int32_t y)
@@ -2460,38 +2580,62 @@ weston_text_cursor_position_notify(struct weston_surface *surface,
 }
 
 WL_EXPORT void
-weston_output_update_zoom(struct weston_output *output, wl_fixed_t fx, wl_fixed_t fy, int text_cursor)
+weston_output_update_zoom(struct weston_output *output, wl_fixed_t fx,
+							wl_fixed_t fy, int text_cursor)
 {
 	int32_t x, y;
-	float trans_min, trans_max;
+	float level = output->zoom.spring.z.current;
 
 	if (output->zoom.level >= 1.0)
 		return;
 
+	output->zoom.fx = fx;
+	output->zoom.fy = fy;
 	x = wl_fixed_to_int(fx);
 	y = wl_fixed_to_int(fy);
 
-	trans_max = output->zoom.level * 2 - output->zoom.level;
-	trans_min = -trans_max;
+	output->zoom.trans_max = level * 2 - level;
+	output->zoom.trans_min = -output->zoom.trans_max;
 
 	output->zoom.trans_x = ((((float)(x - output->x) / output->current->width) *
-					(output->zoom.level * 2)) - output->zoom.level) *
-					(text_cursor ? (1 / output->zoom.level) : 1);
+					(level * 2)) - level) *
+					(text_cursor ? (1 / level) : 1);
 	output->zoom.trans_y = ((((float)(y - output->y) / output->current->height) *
-					(output->zoom.level * 2)) - output->zoom.level) *
-					(text_cursor ? (1 / output->zoom.level) : 1);
-
-	if (output->zoom.trans_x > trans_max)
-		output->zoom.trans_x = trans_max;
-	else if (output->zoom.trans_x < trans_min)
-		output->zoom.trans_x = trans_min;
-	if (output->zoom.trans_y > trans_max)
-		output->zoom.trans_y = trans_max;
-	else if (output->zoom.trans_y < trans_min)
-		output->zoom.trans_y = trans_min;
+					(level * 2)) - level) *
+					(text_cursor ? (1 / level) : 1);
+
+	if (!text_cursor && output->zoom.animation.moving) {
+		/* This condition means we're transitioning from text cursor
+		 * position to mouse pointer. Here we want to get back to tracking
+		 * the pointer ASAP. */
+		output->zoom.spring.x.current +=
+			(output->zoom.trans_x - output->zoom.spring.x.current) * 0.005;
+		output->zoom.spring.y.current +=
+			(output->zoom.trans_y - output->zoom.spring.y.current) * 0.005;
+		if (output->zoom.spring.x.k < 600 ||
+		    output->zoom.spring.y.k < 600) {
+			output->zoom.spring.x.k += 10;
+			output->zoom.spring.y.k += 10;
+		}
+		output->zoom.spring.x.done = 0.02;
+		output->zoom.spring.y.done = 0.02;
+	}
 
-	output->dirty = 1;
-	weston_output_damage(output);
+	if (output->zoom.trans_x > output->zoom.trans_max)
+		output->zoom.trans_x = output->zoom.trans_max;
+	else if (output->zoom.trans_x < output->zoom.trans_min)
+		output->zoom.trans_x = output->zoom.trans_min;
+	if (output->zoom.trans_y > output->zoom.trans_max)
+		output->zoom.trans_y = output->zoom.trans_max;
+	else if (output->zoom.trans_y < output->zoom.trans_min)
+		output->zoom.trans_y = output->zoom.trans_min;
+
+	output->zoom.spring.z.target = output->zoom.level;
+	output->zoom.spring.x.target = output->zoom.trans_x;
+	output->zoom.spring.y.target = output->zoom.trans_y;
+
+	weston_zoom_transition(output, text_cursor != output->zoom.last_transition);
+	output->zoom.last_transition = text_cursor;
 }
 
 WL_EXPORT void
@@ -2513,10 +2657,19 @@ weston_output_update_matrix(struct weston_output *output)
 			    flip * 2.0 / (output->current->height + output->border.top + output->border.bottom), 1);
 
 	if (output->zoom.active) {
-		magnification = 1 / (1 - output->zoom.level);
+		magnification = 1 / (1 - output->zoom.spring.z.current);
 		weston_matrix_init(&camera);
 		weston_matrix_init(&modelview);
-		weston_matrix_translate(&camera, output->zoom.trans_x, flip * output->zoom.trans_y, 0);
+		if (output->zoom.animation.moving)
+			weston_matrix_translate(&camera, output->zoom.spring.x.current,
+						  flip * output->zoom.spring.y.current, 0);
+		else {
+			weston_output_update_zoom(output, output->zoom.fx,
+							  output->zoom.fy,
+							  output->zoom.last_transition);
+			weston_matrix_translate(&camera, output->zoom.trans_x,
+						  flip * output->zoom.trans_y, 0);
+		}
 		weston_matrix_invert(&modelview, &camera);
 		weston_matrix_scale(&modelview, magnification, magnification, 1.0);
 		weston_matrix_multiply(&output->matrix, &modelview);
@@ -2554,10 +2707,19 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
 	wl_list_init(&output->read_pixels_list);
 
 	output->zoom.active = 0;
-	output->zoom.increment = 0.05;
+	output->zoom.animation.moving = 0;
+	output->zoom.animation.zooming = 0;
+	output->zoom.last_transition = 0;
+	output->zoom.increment = 0.1;
+	output->zoom.maximum_level = 0.95;
 	output->zoom.level = 0.0;
+	output->zoom.animation.from_level = 0.0;
+	output->zoom.animation.from_x = 0.0;
+	output->zoom.animation.from_y = 0.0;
 	output->zoom.trans_x = 0.0;
 	output->zoom.trans_y = 0.0;
+	output->zoom.animation.z.frame = weston_zoom_frame_z;
+	output->zoom.animation.xy.frame = weston_zoom_frame_xy;
 
 	output->flags = flags;
 	weston_output_move(output, x, y);
diff --git a/src/compositor.h b/src/compositor.h
index 82bfb26..be5a2ac 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -73,11 +73,41 @@ struct weston_border {
 	int32_t left, right, top, bottom;
 };
 
+struct weston_animation {
+	void (*frame)(struct weston_animation *animation,
+		      struct weston_output *output, uint32_t msecs);
+	struct wl_list link;
+};
+
+struct weston_spring {
+	double k;
+	double friction;
+	double current;
+	double target;
+	double previous;
+	double done;
+	uint32_t timestamp;
+};
+
 struct weston_output_zoom {
 	int active;
 	float increment;
+	float maximum_level;
 	float level;
+	int fx, fy;
 	float trans_x, trans_y;
+	float trans_min, trans_max;
+	int last_transition;
+	struct {
+		struct weston_animation xy, z;
+		float from_level;
+		float from_x, from_y;
+		int moving;
+		int zooming;
+	} animation;
+	struct {
+		struct weston_spring x, y, z;
+	} spring;
 };
 
 /* bit compatible with drm definitions. */
@@ -173,21 +203,6 @@ struct weston_shader {
 	GLint opaque_uniform;
 };
 
-struct weston_animation {
-	void (*frame)(struct weston_animation *animation,
-		      struct weston_output *output, uint32_t msecs);
-	struct wl_list link;
-};
-
-struct weston_spring {
-	double k;
-	double friction;
-	double current;
-	double target;
-	double previous;
-	uint32_t timestamp;
-};
-
 enum {
 	WESTON_COMPOSITOR_ACTIVE,
 	WESTON_COMPOSITOR_IDLE,		/* shell->unlock called on activity */
diff --git a/src/shell.c b/src/shell.c
index 1df9c64..d038c84 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -391,8 +391,7 @@ unresponsive_fade_frame(struct weston_animation *animation,
 			wl_list_remove(&shsurf->unresponsive_animation.current.link);
 			shsurf->unresponsive_animation.exists = 0;
 		}
-	}
-	else {
+	} else {
 		while (step < msecs - shsurf->unresponsive_animation.timestamp) {
 			if (surface->saturation < 255)
 				surface->saturation += 5;
@@ -1635,7 +1634,6 @@ zoom_binding(struct wl_seat *seat, uint32_t time,
 	struct weston_seat *ws = (struct weston_seat *) seat;
 	struct weston_compositor *compositor = ws->compositor;
 	struct weston_output *output;
-	float maximum_level;
 
 	wl_list_for_each(output, &compositor->output_list, link) {
 		if (pixman_region32_contains_point(&output->region,
@@ -1645,15 +1643,11 @@ zoom_binding(struct wl_seat *seat, uint32_t time,
 			output->zoom.active = 1;
 			output->zoom.level += output->zoom.increment * value;
 
-			if (output->zoom.level <= 0.0) {
-				output->zoom.active = 0;
+			if (output->zoom.level < 0.0)
 				output->zoom.level = 0.0;
-			}
-
-			maximum_level = 1 - output->zoom.increment;
 
-			if (output->zoom.level > maximum_level)
-				output->zoom.level = maximum_level;
+			if (output->zoom.level > output->zoom.maximum_level)
+				output->zoom.level = output->zoom.maximum_level;
 
 			weston_output_update_zoom(output,
 			                          seat->pointer->x,
diff --git a/src/util.c b/src/util.c
index b06efd0..44910f1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -39,6 +39,7 @@ weston_spring_init(struct weston_spring *spring,
 	spring->current = current;
 	spring->previous = current;
 	spring->target = target;
+	spring->done = 0.0002;
 }
 
 WL_EXPORT void
@@ -47,7 +48,7 @@ weston_spring_update(struct weston_spring *spring, uint32_t msec)
 	double force, v, current, step;
 
 	step = 0.01;
-	while (4 < msec - spring->timestamp) {
+	while (4 < (int)(msec - spring->timestamp)) {
 		current = spring->current;
 		v = current - spring->previous;
 		force = spring->k * (spring->target - current) / 10.0 +
@@ -81,8 +82,8 @@ weston_spring_update(struct weston_spring *spring, uint32_t msec)
 WL_EXPORT int
 weston_spring_done(struct weston_spring *spring)
 {
-	return fabs(spring->previous - spring->target) < 0.0002 &&
-		fabs(spring->current - spring->target) < 0.0002;
+	return fabs(spring->previous - spring->target) < spring->done &&
+		fabs(spring->current - spring->target) < spring->done;
 }
 
 struct weston_zoom {
-- 
1.7.7.6



More information about the wayland-devel mailing list