[PATCH weston 4/4 v2] Implement animated zoom transitions.

Scott Moreau oreaus at gmail.com
Mon May 21 01:24:31 PDT 2012


---

I noticed that dual output was broken so I fixed it up a bit. There is
still a reproducible crash when zooming one output and then another,
when both are animating simultaneously. One of the output's animations
is removed when it finishes and then for some reason, there is a bogus
animation pointer in the animation_list which causes the crash. Not
really sure what's wrong with it yet.

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

diff --git a/src/compositor.c b/src/compositor.c
index b0b0f75..1759591 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2439,6 +2439,125 @@ 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);
+		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,
+			       &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 +2579,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 +2656,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 +2706,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