<br><br><div class="gmail_quote">2012/2/21 Kristian Høgsberg <span dir="ltr"><<a href="mailto:krh@bitplanet.net">krh@bitplanet.net</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Mon, Feb 20, 2012 at 11:56 PM, Scott Moreau <<a href="mailto:oreaus@gmail.com">oreaus@gmail.com</a>> wrote:<br>
> Implement a camera/modelview matrix for transforms to simulate camera movement.<br>
> Ideally, we would want to use <modifier>+Scroll but that will have to wait<br>
> for axis events. For now we use keyboard grabs. Zoom in/out with Super+Up/Down.<br>
> Zoom area follows mouse pointer.<br>
<br>
</div>Very cool! I like it, but there's a few comments below.<br>
<br>
thanks,<br>
Kristian<br>
<div><div class="h5"><br>
> ---<br>
> src/compositor.c | 41 +++++++++++++++++++++++-<br>
> src/compositor.h | 12 +++++++<br>
> src/shell.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
> 3 files changed, 143 insertions(+), 1 deletions(-)<br>
><br>
> diff --git a/src/compositor.c b/src/compositor.c<br>
> index 8339e6c..ccbccd4 100644<br>
> --- a/src/compositor.c<br>
> +++ b/src/compositor.c<br>
> @@ -925,6 +925,7 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
> struct weston_surface *es;<br>
> struct weston_animation *animation, *next;<br>
> struct weston_frame_callback *cb, *cnext;<br>
> + struct weston_matrix modelview;<br>
> pixman_region32_t opaque, new_damage, total_damage,<br>
> overlap, surface_overlap;<br>
> int32_t width, height;<br>
> @@ -937,6 +938,12 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
> output->border.top + output->border.bottom;<br>
> glViewport(0, 0, width, height);<br>
><br>
> + weston_matrix_init(&output->camera_matrix);<br>
> + weston_matrix_translate(&output->camera_matrix,<br>
> + output->zoom.trans_x,<br>
> + output->zoom.trans_y, 0);<br>
> + weston_matrix_invert(&modelview, &output->camera_matrix);<br>
> +<br>
<br>
</div></div>I think we want to move the output->matrix computation out in a<br>
weston_output_update_matrix() functions and then just roll the zoom<br>
math into that. Then in weston_output_move() or the zoom functions,<br>
when we update the output transform, we just mark it dirty and<br>
recompute it in weston_output_repaint().<br></blockquote><div><br>Yes, this sounds like it would be more versatile.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
> pixman_region32_init(&new_damage);<br>
> pixman_region32_init(&opaque);<br>
> pixman_region32_init(&overlap);<br>
> @@ -953,6 +960,9 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
> pixman_region32_fini(&surface_overlap);<br>
> pixman_region32_union(&overlap, &overlap,<br>
> &es->transform.boundingbox);<br>
> + glUniform1f(es->shader->zoom_uniform, output->zoom.level);<br>
> + glUniformMatrix4fv(es->shader->modelview_uniform,<br>
> + 1, GL_FALSE, modelview.d);<br>
<br>
</div>Need to do this in weston_surface_draw so we update the right shader<br>
uniform, but if we roll the zoom transform into output->matrix as<br>
described above that will happen automatically.<br></blockquote><div><br>Noted.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
> }<br>
><br>
> weston_output_set_cursor(output, ec->input_device);<br>
> @@ -1322,6 +1332,9 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)<br>
> max_x = output->x + output->current->width;<br>
> if (output->y + output->current->height > max_y)<br>
> max_y = output->y + output->current->height;<br>
> + if (output->zoom.active &&<br>
> + pixman_region32_contains_point(&output->region, x, y, NULL))<br>
> + zoom_update(output, x, y);<br>
<br>
</div>There's an edge case here (literally!) since if the pointer is on the<br>
screen edge, the zoom position doesn't update. If I move along the<br>
edge, the view doesn't change. Only when I move it into the screen,<br>
away from the edge does the position update.<br></blockquote><div><br>Admittedly, I haven't tested it outside of X. I will have a look into it.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
> }<br>
><br>
> if (!x_valid) {<br>
> @@ -1850,12 +1863,14 @@ bind_output(struct wl_client *client,<br>
><br>
> static const char vertex_shader[] =<br>
> "uniform mat4 proj;\n"<br>
> + "uniform mat4 modelview;\n"<br>
> + "uniform float zoom;\n"<br>
> "attribute vec2 position;\n"<br>
> "attribute vec2 texcoord;\n"<br>
> "varying vec2 v_texcoord;\n"<br>
> "void main()\n"<br>
> "{\n"<br>
> - " gl_Position = proj * vec4(position, 0.0, 1.0);\n"<br>
> + " gl_Position = proj * (modelview * vec4(position, 0.0, zoom));\n"<br>
> " v_texcoord = texcoord;\n"<br>
> "}\n";<br>
<br>
</div>Again, if we roll the zoom into the output matrix we don't need this.<br></blockquote><div><br>Ok.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
> @@ -1929,6 +1944,8 @@ weston_shader_init(struct weston_shader *shader,<br>
> }<br>
><br>
> shader->proj_uniform = glGetUniformLocation(shader->program, "proj");<br>
> + shader->modelview_uniform = glGetUniformLocation(shader->program, "modelview");<br>
> + shader->zoom_uniform = glGetUniformLocation(shader->program, "zoom");<br>
> shader->tex_uniform = glGetUniformLocation(shader->program, "tex");<br>
> shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");<br>
> shader->color_uniform = glGetUniformLocation(shader->program, "color");<br>
> @@ -1946,6 +1963,21 @@ weston_output_destroy(struct weston_output *output)<br>
> }<br>
><br>
> WL_EXPORT void<br>
> +zoom_update(struct weston_output *output, int x, int y)<br>
> +{<br>
> + if (output->zoom.level <= 0)<br>
> + return;<br>
> +<br>
> + float ratio = (1 / output->zoom.level) - 1;<br>
> +<br>
> + output->zoom.trans_x = (output->mm_width * ratio) *<br>
> + ((float)x / output->mm_width);<br>
> + output->zoom.trans_y = (output->mm_height * ratio) *<br>
> + ((float)y / output->mm_height);<br>
> + weston_output_damage(output);<br>
> +}<br>
<br>
</div>output->mm_width is the physical width of the display (in millimeter),<br>
not the number of pixels. Use output->current->width.</blockquote><div><br>Ah, I did not realize this<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
And this
should be in the weston_output_matrix_update() function mentioned<br>
above.<br></blockquote><div><br>Right.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
> +WL_EXPORT void<br>
> weston_output_move(struct weston_output *output, int x, int y)<br>
> {<br>
> int flip;<br>
> @@ -1985,6 +2017,13 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
> output->mm_width = width;<br>
> output->mm_height = height;<br>
><br>
> + output->zoom.active = 0;<br>
> + output->zoom.level = 1.0;<br>
> + output->zoom.trans_x = 0.0;<br>
> + output->zoom.trans_y = 0.0;<br>
> +<br>
> + weston_matrix_init(&output->camera_matrix);<br>
> +<br>
> output->flags = flags;<br>
> weston_output_move(output, x, y);<br>
><br>
> diff --git a/src/compositor.h b/src/compositor.h<br>
> index 4c82e79..66ec688 100644<br>
> --- a/src/compositor.h<br>
> +++ b/src/compositor.h<br>
> @@ -54,10 +54,17 @@ struct weston_border {<br>
> int32_t left, right, top, bottom;<br>
> };<br>
><br>
> +struct weston_output_zoom {<br>
> + int active;<br>
> + float level;<br>
> + int trans_x, trans_y;<br>
> +};<br>
> +<br>
> struct weston_output {<br>
> struct wl_list link;<br>
> struct weston_compositor *compositor;<br>
> struct weston_matrix matrix;<br>
> + struct weston_matrix camera_matrix;<br>
> struct wl_list frame_callback_list;<br>
> int32_t x, y, mm_width, mm_height;<br>
> struct weston_border border;<br>
> @@ -66,6 +73,7 @@ struct weston_output {<br>
> uint32_t flags;<br>
> int repaint_needed;<br>
> int repaint_scheduled;<br>
> + struct weston_output_zoom zoom;<br>
><br>
> char *make, *model;<br>
> uint32_t subpixel;<br>
> @@ -100,6 +108,8 @@ struct weston_shader {<br>
> GLuint program;<br>
> GLuint vertex_shader, fragment_shader;<br>
> GLint proj_uniform;<br>
> + GLint modelview_uniform;<br>
> + GLint zoom_uniform;<br>
> GLint tex_uniform;<br>
> GLint alpha_uniform;<br>
> GLint color_uniform;<br>
> @@ -414,6 +424,8 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)<br>
> void<br>
> weston_compositor_shutdown(struct weston_compositor *ec);<br>
> void<br>
> +zoom_update(struct weston_output *output, int x, int y);<br>
> +void<br>
> weston_output_move(struct weston_output *output, int x, int y);<br>
> void<br>
> weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
> diff --git a/src/shell.c b/src/shell.c<br>
> index fa165e2..ee406f0 100644<br>
> --- a/src/shell.c<br>
> +++ b/src/shell.c<br>
> @@ -113,6 +113,11 @@ struct shell_surface {<br>
> struct wl_list link;<br>
> };<br>
><br>
> +struct weston_zoom_grab {<br>
> + struct wl_keyboard_grab grab;<br>
> + uint32_t key;<br>
> +};<br>
> +<br>
> struct weston_move_grab {<br>
> struct wl_pointer_grab grab;<br>
> struct weston_surface *surface;<br>
> @@ -1035,6 +1040,88 @@ resize_binding(struct wl_input_device *device, uint32_t time,<br>
> }<br>
><br>
> static void<br>
> +zoom_grab_key(struct wl_keyboard_grab *grab,<br>
> + uint32_t time, uint32_t key, int32_t state)<br>
> +{<br>
> + struct weston_zoom_grab *zoom;<br>
> + zoom = container_of(grab, struct weston_zoom_grab, grab);<br>
> +<br>
> + if (state == 0) {<br>
> + wl_input_device_end_keyboard_grab(grab->input_device, time);<br>
> + free(zoom);<br>
> + }<br>
> +}<br>
> +<br>
> +static const struct wl_keyboard_grab_interface zoom_grab_interface = {<br>
> + zoom_grab_key,<br>
> +};<br>
> +<br>
> +static void<br>
> +zoom_in_binding(struct wl_input_device *device, uint32_t time,<br>
> + uint32_t key, uint32_t button, uint32_t state, void *data)<br>
> +{<br>
> + struct weston_input_device *wd = (struct weston_input_device *) device;<br>
> + struct weston_compositor *compositor = wd->compositor;<br>
> + struct weston_output *output;<br>
> + struct weston_zoom_grab *zoom;<br>
> +<br>
> + zoom = malloc(sizeof *zoom);<br>
> + if (!zoom)<br>
> + return;<br>
> +<br>
> + zoom->grab.interface = &zoom_grab_interface;<br>
> +<br>
> + wl_input_device_start_keyboard_grab(&wd->input_device, &zoom->grab, time);<br>
<br>
</div></div>Why do you use a key grab here? Oh, it's to avoid delivering the<br>
event right? I think we just need to make bindings swallow the event<br>
(key press and release for the key in question, for buttons too).</blockquote><div><br>Indeed.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The
grab method you're using breaks if somebody presses and then releases<br>
another key or the super key first.<br></blockquote><div><br>Yes, I realize this. I just wanted to make sure there was no chance of not freeing<br>allocated memory.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Oh, as a feature request, could we make shift+super do integer<br>
scaling? As it is, I have to press 10 times to get to double size,<br>
triple size isn't possible, and 10 more times to do 4 times zoom.</blockquote><div><br>Absolutely.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
We may also want GL_LINEAR filtering when we're zoomed to a non-integer<br>
multiple.<br></blockquote><div><br>Yes, indeed.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
> + wl_list_for_each(output, &compositor->output_list, link) {<br>
> + if (pixman_region32_contains_point(&output->region,<br>
> + device->x, device->y, NULL)) {<br>
> + output->zoom.active = 1;<br>
> + output->zoom.level -= 0.05;<br>
> + if (output->zoom.level > 1.0)<br>
> + output->zoom.level = 1.0;<br>
> + if (output->zoom.level < 0.0)<br>
> + output->zoom.level = 0.05;<br>
> +<br>
> + zoom_update(output, device->x, device->y);<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +static void<br>
> +zoom_out_binding(struct wl_input_device *device, uint32_t time,<br>
> + uint32_t key, uint32_t button, uint32_t state, void *data)<br>
> +{<br>
> + struct weston_input_device *wd = (struct weston_input_device *) device;<br>
> + struct weston_compositor *compositor = wd->compositor;<br>
> + struct weston_output *output;<br>
> + struct weston_zoom_grab *zoom;<br>
> +<br>
> + zoom = malloc(sizeof *zoom);<br>
> + if (!zoom)<br>
> + return;<br>
> +<br>
> + zoom->grab.interface = &zoom_grab_interface;<br>
> +<br>
> + wl_input_device_start_keyboard_grab(&wd->input_device, &zoom->grab, time);<br>
> +<br>
> + wl_list_for_each(output, &compositor->output_list, link) {<br>
> + if (pixman_region32_contains_point(&output->region,<br>
> + device->x, device->y, NULL)) {<br>
> + output->zoom.level += 0.05;<br>
> + if (output->zoom.level > 1.0)<br>
> + output->zoom.level = 1.0;<br>
> + if (output->zoom.level < 0.0) {<br>
> + output->zoom.active = 0;<br>
> + output->zoom.level = 0.0;<br>
> + }<br>
> +<br>
> + zoom_update(output, device->x, device->y);<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +static void<br>
> terminate_binding(struct wl_input_device *device, uint32_t time,<br>
> uint32_t key, uint32_t button, uint32_t state, void *data)<br>
> {<br>
> @@ -1827,6 +1914,10 @@ shell_init(struct weston_compositor *ec)<br>
> move_binding, shell);<br>
> weston_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,<br>
> resize_binding, shell);<br>
> + weston_compositor_add_binding(ec, KEY_UP, 0, MODIFIER_SUPER,<br>
> + zoom_in_binding, shell);<br>
> + weston_compositor_add_binding(ec, KEY_DOWN, 0, MODIFIER_SUPER,<br>
> + zoom_out_binding, shell);<br>
> weston_compositor_add_binding(ec, KEY_BACKSPACE, 0,<br>
> MODIFIER_CTRL | MODIFIER_ALT,<br>
> terminate_binding, ec);<br>
> --<br>
> 1.7.4.1<br>
><br>
</div></div>> _______________________________________________<br>
> wayland-devel mailing list<br>
> <a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</blockquote></div><br><br>Thanks for your input. I will work on a v3 patch now.<br><br><br>Cheers,<br><br>Scott<br>