[RFC] compositor: Introduce composite zoom. v1

Scott Moreau oreaus at gmail.com
Mon Feb 13 14:26:16 PST 2012


Implements a modelview matrix for transforms to simulate camera movement.
Ideally, we would want to use <modifier>+Scroll but that will have to
wait for axis events to come. For now we double check for the binding
in notify_key as a quick-n-dirty hack to avoid sending unwanted events.
Zoom in/out with Super+Up/Down. Zoom area follows mouse pointer.

---
 src/compositor.c |   43 +++++++++++++++++++++++++++++++++++++++++--
 src/compositor.h |   15 +++++++++++++++
 src/shell.c      |   43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index ab90ded..de4f9f4 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -307,6 +307,21 @@ surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
 				  ceilf(max_x) - int_x, ceilf(max_y) - int_y);
 }
 
+WL_EXPORT void
+weston_update_zoom(struct weston_output *output, int x, int y)
+{
+	if (output->zoom.level <= 0.0)
+		return;
+
+	GLfloat ratio = (1 / output->zoom.level) - 1;
+
+	output->zoom.trans_x = (output->mm_width * ratio) *
+								((float)x / output->mm_width);
+	output->zoom.trans_y = (output->mm_height * ratio) *
+								((float)y  / output->mm_height);
+	weston_output_damage(output);
+}
+
 static void
 weston_surface_update_transform_disable(struct weston_surface *surface)
 {
@@ -774,7 +789,16 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output)
 		glUseProgram(es->shader->program);
 		ec->current_shader = es->shader;
 	}
+	glUniform1f(es->shader->zoom_uniform, output->zoom.level);
 
+	struct weston_matrix modelview_inverse;
+	weston_matrix_init(&output->modelview_matrix);
+	weston_matrix_translate(&output->modelview_matrix,
+											output->zoom.trans_x,
+											output->zoom.trans_y, 0);
+	weston_matrix_invert(&modelview_inverse, &output->modelview_matrix);
+	glUniformMatrix4fv(es->shader->modelview_uniform,
+			   1, GL_FALSE, modelview_inverse.d);
 	glUniformMatrix4fv(es->shader->proj_uniform,
 			   1, GL_FALSE, output->matrix.d);
 	glUniform1i(es->shader->tex_uniform, 0);
@@ -1349,6 +1373,8 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
 			max_x = output->x + output->current->width;
 		if (output->y + output->current->height > max_y)
 			max_y = output->y + output->current->height;
+		if (output->zoom.active)
+			weston_update_zoom(output, x, y);
 	}
 	
 	if (!x_valid) {
@@ -1466,6 +1492,9 @@ notify_key(struct wl_input_device *device,
 
 	weston_compositor_run_binding(compositor, wd, time, key, 0, state);
 
+	if (wd->modifier_state & MODIFIER_SUPER && (key == KEY_UP || key == KEY_DOWN))
+		return;
+
 	update_modifier_state(wd, key, state);
 	end = device->keys.data + device->keys.size;
 	for (k = device->keys.data; k < end; k++) {
@@ -1815,12 +1844,14 @@ bind_output(struct wl_client *client,
 
 static const char vertex_shader[] =
 	"uniform mat4 proj;\n"
+	"uniform mat4 modelview;\n"
+	"uniform float zoom;\n"
 	"attribute vec2 position;\n"
 	"attribute vec2 texcoord;\n"
 	"varying vec2 v_texcoord;\n"
 	"void main()\n"
 	"{\n"
-	"   gl_Position = proj * vec4(position, 0.0, 1.0);\n"
+	"   gl_Position = proj * (modelview * vec4(position, 0.0, zoom));\n"
 	"   v_texcoord = texcoord;\n"
 	"}\n";
 
@@ -1894,6 +1925,8 @@ weston_shader_init(struct weston_shader *shader,
 	}
 
 	shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
+	shader->modelview_uniform = glGetUniformLocation(shader->program, "modelview");
+	shader->zoom_uniform = glGetUniformLocation(shader->program, "zoom");
 	shader->tex_uniform = glGetUniformLocation(shader->program, "tex");
 	shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
 	shader->color_uniform = glGetUniformLocation(shader->program, "color");
@@ -1950,6 +1983,12 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
 	output->mm_width = width;
 	output->mm_height = height;
 
+	output->zoom.active = 0;
+	output->zoom.increment = 0.05;
+	output->zoom.level = 1.0;
+	output->zoom.trans_x = 0.0;
+	output->zoom.trans_y = 0.0;
+
 	output->flags = flags;
 	weston_output_move(output, x, y);
 
diff --git a/src/compositor.h b/src/compositor.h
index 966d3f4..0f5827e 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -54,10 +54,19 @@ struct weston_border {
 	int32_t left, right, top, bottom;
 };
 
+struct weston_composite_zoom {
+	int active;
+	/* 1.0 is no zoom, 0.0 is 100% zoomed in */
+	GLfloat level;
+	float increment;
+	int trans_x, trans_y;
+};
+
 struct weston_output {
 	struct wl_list link;
 	struct weston_compositor *compositor;
 	struct weston_matrix matrix;
+	struct weston_matrix modelview_matrix;
 	struct wl_list frame_callback_list;
 	int32_t x, y, mm_width, mm_height;
 	struct weston_border border;
@@ -66,6 +75,7 @@ struct weston_output {
 	uint32_t flags;
 	int repaint_needed;
 	int repaint_scheduled;
+	struct weston_composite_zoom zoom;
 
 	char *make, *model;
 	uint32_t subpixel;
@@ -105,6 +115,8 @@ struct weston_shader {
 	GLuint program;
 	GLuint vertex_shader, fragment_shader;
 	GLint proj_uniform;
+	GLint modelview_uniform;
+	GLint zoom_uniform;
 	GLint tex_uniform;
 	GLint alpha_uniform;
 	GLint color_uniform;
@@ -325,6 +337,9 @@ void
 weston_surface_draw(struct weston_surface *es, struct weston_output *output);
 
 void
+weston_update_zoom(struct weston_output *output, int x, int y);
+
+void
 notify_motion(struct wl_input_device *device,
 	      uint32_t time, int x, int y);
 void
diff --git a/src/shell.c b/src/shell.c
index 66c4f01..6b2ffc0 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -964,6 +964,45 @@ resize_binding(struct wl_input_device *device, uint32_t time,
 }
 
 static void
+zoom_in_binding(struct wl_input_device *device, uint32_t time,
+	       uint32_t key, uint32_t button, uint32_t state, void *data)
+{
+	struct weston_input_device *wd = (struct weston_input_device *) device;
+	struct weston_compositor *compositor = wd->compositor;
+	struct weston_output *output;
+	output = container_of(compositor->output_list.next,
+			struct weston_output, link);
+
+	output->zoom.active = 1;
+	output->zoom.level -= output->zoom.increment;
+	if (output->zoom.level > 1.0)
+		output->zoom.level = 1.0;
+	if (output->zoom.level <= output->zoom.increment)
+		output->zoom.level = output->zoom.increment;
+
+	weston_update_zoom(output, device->x, device->y);
+}
+
+static void
+zoom_out_binding(struct wl_input_device *device, uint32_t time,
+	       uint32_t key, uint32_t button, uint32_t state, void *data)
+{
+	struct weston_input_device *wd = (struct weston_input_device *) device;
+	struct weston_compositor *compositor = wd->compositor;
+	struct weston_output *output;
+	output = container_of(compositor->output_list.next,
+			struct weston_output, link);
+
+	output->zoom.level += output->zoom.increment;
+	if (output->zoom.level > 1.0) {
+		output->zoom.active = 0;
+		output->zoom.level = 1.0;
+	}
+
+	weston_update_zoom(output, device->x, device->y);
+}
+
+static void
 terminate_binding(struct wl_input_device *device, uint32_t time,
 		  uint32_t key, uint32_t button, uint32_t state, void *data)
 {
@@ -1618,6 +1657,10 @@ shell_init(struct weston_compositor *ec)
 				    move_binding, shell);
 	weston_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
 				    resize_binding, shell);
+	weston_compositor_add_binding(ec, KEY_UP, 0, MODIFIER_SUPER,
+				    zoom_in_binding, shell);
+	weston_compositor_add_binding(ec, KEY_DOWN, 0, MODIFIER_SUPER,
+				    zoom_out_binding, shell);
 	weston_compositor_add_binding(ec, KEY_BACKSPACE, 0,
 				    MODIFIER_CTRL | MODIFIER_ALT,
 				    terminate_binding, ec);
-- 
1.7.4.1



More information about the wayland-devel mailing list