[RFC] Introduce output zoom.
Scott Moreau
oreaus at gmail.com
Tue Feb 21 16:27:41 PST 2012
2012/2/21 Kristian Høgsberg <krh at bitplanet.net>
> On Mon, Feb 20, 2012 at 11:56 PM, Scott Moreau <oreaus at gmail.com> wrote:
> > Implement a camera/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. For now we use keyboard grabs. Zoom in/out with
> Super+Up/Down.
> > Zoom area follows mouse pointer.
>
> Very cool! I like it, but there's a few comments below.
>
> thanks,
> Kristian
>
> > ---
> > src/compositor.c | 41 +++++++++++++++++++++++-
> > src/compositor.h | 12 +++++++
> > src/shell.c | 91
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 143 insertions(+), 1 deletions(-)
> >
> > diff --git a/src/compositor.c b/src/compositor.c
> > index 8339e6c..ccbccd4 100644
> > --- a/src/compositor.c
> > +++ b/src/compositor.c
> > @@ -925,6 +925,7 @@ weston_output_repaint(struct weston_output *output,
> int msecs)
> > struct weston_surface *es;
> > struct weston_animation *animation, *next;
> > struct weston_frame_callback *cb, *cnext;
> > + struct weston_matrix modelview;
> > pixman_region32_t opaque, new_damage, total_damage,
> > overlap, surface_overlap;
> > int32_t width, height;
> > @@ -937,6 +938,12 @@ weston_output_repaint(struct weston_output *output,
> int msecs)
> > output->border.top + output->border.bottom;
> > glViewport(0, 0, width, height);
> >
> > + weston_matrix_init(&output->camera_matrix);
> > + weston_matrix_translate(&output->camera_matrix,
> > + output->zoom.trans_x,
> > + output->zoom.trans_y, 0);
> > + weston_matrix_invert(&modelview, &output->camera_matrix);
> > +
>
> I think we want to move the output->matrix computation out in a
> weston_output_update_matrix() functions and then just roll the zoom
> math into that. Then in weston_output_move() or the zoom functions,
> when we update the output transform, we just mark it dirty and
> recompute it in weston_output_repaint().
>
Yes, this sounds like it would be more versatile.
> > pixman_region32_init(&new_damage);
> > pixman_region32_init(&opaque);
> > pixman_region32_init(&overlap);
> > @@ -953,6 +960,9 @@ weston_output_repaint(struct weston_output *output,
> int msecs)
> > pixman_region32_fini(&surface_overlap);
> > pixman_region32_union(&overlap, &overlap,
> > &es->transform.boundingbox);
> > + glUniform1f(es->shader->zoom_uniform,
> output->zoom.level);
> > + glUniformMatrix4fv(es->shader->modelview_uniform,
> > + 1, GL_FALSE, modelview.d);
>
> Need to do this in weston_surface_draw so we update the right shader
> uniform, but if we roll the zoom transform into output->matrix as
> described above that will happen automatically.
>
Noted.
> > }
> >
> > weston_output_set_cursor(output, ec->input_device);
> > @@ -1322,6 +1332,9 @@ 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 &&
> > + pixman_region32_contains_point(&output->region, x,
> y, NULL))
> > + zoom_update(output, x, y);
>
> There's an edge case here (literally!) since if the pointer is on the
> screen edge, the zoom position doesn't update. If I move along the
> edge, the view doesn't change. Only when I move it into the screen,
> away from the edge does the position update.
>
Admittedly, I haven't tested it outside of X. I will have a look into it.
> > }
> >
> > if (!x_valid) {
> > @@ -1850,12 +1863,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";
>
> Again, if we roll the zoom into the output matrix we don't need this.
>
Ok.
> > @@ -1929,6 +1944,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");
> > @@ -1946,6 +1963,21 @@ weston_output_destroy(struct weston_output
> *output)
> > }
> >
> > WL_EXPORT void
> > +zoom_update(struct weston_output *output, int x, int y)
> > +{
> > + if (output->zoom.level <= 0)
> > + return;
> > +
> > + float 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);
> > +}
>
> output->mm_width is the physical width of the display (in millimeter),
> not the number of pixels. Use output->current->width.
Ah, I did not realize this
> And this should be in the weston_output_matrix_update() function mentioned
> above.
>
Right.
>
> > +WL_EXPORT void
> > weston_output_move(struct weston_output *output, int x, int y)
> > {
> > int flip;
> > @@ -1985,6 +2017,13 @@ 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.level = 1.0;
> > + output->zoom.trans_x = 0.0;
> > + output->zoom.trans_y = 0.0;
> > +
> > + weston_matrix_init(&output->camera_matrix);
> > +
> > output->flags = flags;
> > weston_output_move(output, x, y);
> >
> > diff --git a/src/compositor.h b/src/compositor.h
> > index 4c82e79..66ec688 100644
> > --- a/src/compositor.h
> > +++ b/src/compositor.h
> > @@ -54,10 +54,17 @@ struct weston_border {
> > int32_t left, right, top, bottom;
> > };
> >
> > +struct weston_output_zoom {
> > + int active;
> > + float level;
> > + int trans_x, trans_y;
> > +};
> > +
> > struct weston_output {
> > struct wl_list link;
> > struct weston_compositor *compositor;
> > struct weston_matrix matrix;
> > + struct weston_matrix camera_matrix;
> > struct wl_list frame_callback_list;
> > int32_t x, y, mm_width, mm_height;
> > struct weston_border border;
> > @@ -66,6 +73,7 @@ struct weston_output {
> > uint32_t flags;
> > int repaint_needed;
> > int repaint_scheduled;
> > + struct weston_output_zoom zoom;
> >
> > char *make, *model;
> > uint32_t subpixel;
> > @@ -100,6 +108,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;
> > @@ -414,6 +424,8 @@ weston_compositor_init(struct weston_compositor *ec,
> struct wl_display *display)
> > void
> > weston_compositor_shutdown(struct weston_compositor *ec);
> > void
> > +zoom_update(struct weston_output *output, int x, int y);
> > +void
> > weston_output_move(struct weston_output *output, int x, int y);
> > void
> > weston_output_init(struct weston_output *output, struct
> weston_compositor *c,
> > diff --git a/src/shell.c b/src/shell.c
> > index fa165e2..ee406f0 100644
> > --- a/src/shell.c
> > +++ b/src/shell.c
> > @@ -113,6 +113,11 @@ struct shell_surface {
> > struct wl_list link;
> > };
> >
> > +struct weston_zoom_grab {
> > + struct wl_keyboard_grab grab;
> > + uint32_t key;
> > +};
> > +
> > struct weston_move_grab {
> > struct wl_pointer_grab grab;
> > struct weston_surface *surface;
> > @@ -1035,6 +1040,88 @@ resize_binding(struct wl_input_device *device,
> uint32_t time,
> > }
> >
> > static void
> > +zoom_grab_key(struct wl_keyboard_grab *grab,
> > + uint32_t time, uint32_t key, int32_t state)
> > +{
> > + struct weston_zoom_grab *zoom;
> > + zoom = container_of(grab, struct weston_zoom_grab, grab);
> > +
> > + if (state == 0) {
> > + wl_input_device_end_keyboard_grab(grab->input_device,
> time);
> > + free(zoom);
> > + }
> > +}
> > +
> > +static const struct wl_keyboard_grab_interface zoom_grab_interface = {
> > + zoom_grab_key,
> > +};
> > +
> > +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;
> > + struct weston_zoom_grab *zoom;
> > +
> > + zoom = malloc(sizeof *zoom);
> > + if (!zoom)
> > + return;
> > +
> > + zoom->grab.interface = &zoom_grab_interface;
> > +
> > + wl_input_device_start_keyboard_grab(&wd->input_device,
> &zoom->grab, time);
>
> Why do you use a key grab here? Oh, it's to avoid delivering the
> event right? I think we just need to make bindings swallow the event
> (key press and release for the key in question, for buttons too).
Indeed.
> The grab method you're using breaks if somebody presses and then releases
> another key or the super key first.
>
Yes, I realize this. I just wanted to make sure there was no chance of not
freeing
allocated memory.
>
> Oh, as a feature request, could we make shift+super do integer
> scaling? As it is, I have to press 10 times to get to double size,
> triple size isn't possible, and 10 more times to do 4 times zoom.
Absolutely.
> We may also want GL_LINEAR filtering when we're zoomed to a non-integer
> multiple.
>
Yes, indeed.
>
> > + wl_list_for_each(output, &compositor->output_list, link) {
> > + if (pixman_region32_contains_point(&output->region,
> > + device->x, device->y,
> NULL)) {
> > + output->zoom.active = 1;
> > + output->zoom.level -= 0.05;
> > + if (output->zoom.level > 1.0)
> > + output->zoom.level = 1.0;
> > + if (output->zoom.level < 0.0)
> > + output->zoom.level = 0.05;
> > +
> > + zoom_update(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;
> > + struct weston_zoom_grab *zoom;
> > +
> > + zoom = malloc(sizeof *zoom);
> > + if (!zoom)
> > + return;
> > +
> > + zoom->grab.interface = &zoom_grab_interface;
> > +
> > + wl_input_device_start_keyboard_grab(&wd->input_device,
> &zoom->grab, time);
> > +
> > + wl_list_for_each(output, &compositor->output_list, link) {
> > + if (pixman_region32_contains_point(&output->region,
> > + device->x, device->y,
> NULL)) {
> > + output->zoom.level += 0.05;
> > + if (output->zoom.level > 1.0)
> > + output->zoom.level = 1.0;
> > + if (output->zoom.level < 0.0) {
> > + output->zoom.active = 0;
> > + output->zoom.level = 0.0;
> > + }
> > +
> > + zoom_update(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)
> > {
> > @@ -1827,6 +1914,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
> >
> > _______________________________________________
> > wayland-devel mailing list
> > wayland-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
Thanks for your input. I will work on a v3 patch now.
Cheers,
Scott
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20120221/7c9e6171/attachment-0001.html>
More information about the wayland-devel
mailing list