[call for testing] clients: add cliptest program

Birin Sanchez birintxo at gmail.com
Thu Sep 6 03:41:15 PDT 2012


Hi Pekka,

I gave this clipping algorithm a try and I found a weird behaviour that 
I don't know if it is expected of not. See attachment 1.

And this is how to reproduce it:

  * Move the clipping area to get it side by side with the surface, 
you'll see the a green line between the two rectangles.
* Change surface orientation pressing 'n' until you get to the initial 
position

Apart from this the green line showed the intersection on all my tests.

Cheers,

Birin

On 05/09/12 15:37, Pekka Paalanen wrote:
> Cliptest is for controlled testing of the calculate_edges() function in
> compositor.c. The function is copied verbatim into cliptest.c.
>
> Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
> ---
>   clients/Makefile.am |    5 +
>   clients/cliptest.c  |  819 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 824 insertions(+), 0 deletions(-)
>   create mode 100644 clients/cliptest.c
>
> Hi all,
>
> this patch contains a new polygon clipping algorithm for the rectangle-rectangle
> intersection computation, a.k.a calculate_edges() function. Right now, it is
> only in the cliptest program for testing.
>
> I would like to ask people to try to break the algorithm.
>
> Apply this patch, and run cliptest in a Wayland compositor. You will see a blue
> rectangle, which is the clipping area, and a red rectangle which represents
> a surface. The red dot indicates the orientation of the surface.
>
> The algorithm computes the intersection of these two rectangles. In the
> image, the algorithm produces the green line with vertex indices. The
> green line should be exactly the boundary of the intersection (purple). See:
> http://people.collabora.com/~pq/geometry-test-8.png
>
> If you can produce an image, where the green line is wrong, like it was in
> http://people.collabora.com/~pq/geometry-test-5.png
> please, take a screenshot and send it to me.
>
> You can control the rectangles by:
>   *	clip box position: mouse left drag, keys: w a s d
>   *	clip box size: mouse right drag, keys: i j k l
>   *	surface orientation: mouse wheel, keys: n m
>   *	surface transform disable key: r
>
> Also, if you try this, and cannot break it, let me know you tried, still.
>
>
> Thanks,
> pq
>
> diff --git a/clients/Makefile.am b/clients/Makefile.am
> index 1b7fa10..a777772 100644
> --- a/clients/Makefile.am
> +++ b/clients/Makefile.am
> @@ -48,6 +48,7 @@ terminal = weston-terminal
>   clients_programs =				\
>   	flower					\
>   	image					\
> +	cliptest				\
>   	dnd					\
>   	smoke					\
>   	resizor					\
> @@ -88,6 +89,10 @@ weston_terminal_LDADD = $(toolkit_libs) -lutil
>   image_SOURCES = image.c
>   image_LDADD = $(toolkit_libs)
>   
> +cliptest_SOURCES = cliptest.c
> +cliptest_CPPFLAGS = $(AM_CPPFLAGS) $(PIXMAN_CFLAGS)
> +cliptest_LDADD = $(toolkit_libs) $(PIXMAN_LIBS)
> +
>   dnd_SOURCES = dnd.c
>   dnd_LDADD = $(toolkit_libs)
>   
> diff --git a/clients/cliptest.c b/clients/cliptest.c
> new file mode 100644
> index 0000000..9531728
> --- /dev/null
> +++ b/clients/cliptest.c
> @@ -0,0 +1,819 @@
> +/*
> + * Copyright © 2012 Collabora, Ltd.
> + * Copyright © 2012 Rob Clark
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +/* cliptest: for debugging calculate_edges() function, which is copied
> + * from compositor.c.
> + * controls:
> + *	clip box position: mouse left drag, keys: w a s d
> + *	clip box size: mouse right drag, keys: i j k l
> + *	surface orientation: mouse wheel, keys: n m
> + *	surface transform disable key: r
> + */
> +
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <libgen.h>
> +#include <unistd.h>
> +#include <math.h>
> +#include <time.h>
> +#include <pixman.h>
> +#include <cairo.h>
> +#include <assert.h>
> +
> +#include <linux/input.h>
> +#include <wayland-client.h>
> +
> +#include "window.h"
> +
> +typedef float GLfloat;
> +
> +struct geometry {
> +	pixman_box32_t clip;
> +
> +	pixman_box32_t surf;
> +	float s; /* sin phi */
> +	float c; /* cos phi */
> +	float phi;
> +};
> +
> +struct weston_surface {
> +	struct {
> +		int enabled;
> +	} transform;
> +
> +	struct geometry *geometry;
> +};
> +
> +static void
> +weston_surface_to_global_float(struct weston_surface *surface,
> +			       GLfloat sx, GLfloat sy, GLfloat *x, GLfloat *y)
> +{
> +	struct geometry *g = surface->geometry;
> +
> +	/* pure rotation around origin by sine and cosine */
> +	*x = g->c * sx + g->s * sy;
> +	*y = -g->s * sx + g->c * sy;
> +}
> +
> +/* ---------------------- copied begins -----------------------*/
> +
> +struct polygon8 {
> +	GLfloat x[8];
> +	GLfloat y[8];
> +	int n;
> +};
> +
> +struct clip_context {
> +	struct {
> +		GLfloat x;
> +		GLfloat y;
> +	} prev;
> +
> +	struct {
> +		GLfloat x1, y1;
> +		GLfloat x2, y2;
> +	} clip;
> +
> +	struct {
> +		GLfloat *x;
> +		GLfloat *y;
> +	} vertices;
> +};
> +
> +static GLfloat
> +clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
> +		 GLfloat x_arg)
> +{
> +	/* homogenenous line equation, ax + by + c = 0, l = (a, b, c)^T */
> +	GLfloat a, b, c;
> +
> +	/* l = p1 x p2, vector cross product */
> +	a = p1y - p2y;
> +	b = p2x - p1x;
> +	c = p1x * p2y - p1y * p2x;
> +
> +	/* intersection of lines l and x = x_arg; l x (-1, 0, x_arg)^T */
> +	return -(c + a * x_arg) / b;
> +}
> +
> +static GLfloat
> +clip_intersect_x(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
> +		 GLfloat y_arg)
> +{
> +	/* homogenenous line equation, ax + by + c = 0, l = (a, b, c)^T */
> +	GLfloat a, b, c;
> +
> +	/* l = p1 x p2, vector cross product */
> +	a = p1y - p2y;
> +	b = p2x - p1x;
> +	c = p1x * p2y - p1y * p2x;
> +
> +	/* intersection of lines l and y = y_arg; l x (0, -1, y_arg)^T */
> +	return -(b * y_arg + c) / a;
> +}
> +
> +enum path_transition {
> +	PATH_TRANSITION_OUT_TO_OUT = 0,
> +	PATH_TRANSITION_OUT_TO_IN = 1,
> +	PATH_TRANSITION_IN_TO_OUT = 2,
> +	PATH_TRANSITION_IN_TO_IN = 3,
> +};
> +
> +static void
> +clip_append_vertex(struct clip_context *ctx, GLfloat x, GLfloat y)
> +{
> +	*ctx->vertices.x++ = x;
> +	*ctx->vertices.y++ = y;
> +}
> +
> +static enum path_transition
> +path_transition_left_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
> +{
> +	return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
> +}
> +
> +static enum path_transition
> +path_transition_right_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
> +{
> +	return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
> +}
> +
> +static enum path_transition
> +path_transition_top_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
> +{
> +	return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
> +}
> +
> +static enum path_transition
> +path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
> +{
> +	return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
> +}
> +
> +static void
> +clip_polygon_leftright(struct clip_context *ctx,
> +		       enum path_transition transition,
> +		       GLfloat x, GLfloat y, GLfloat clip_x)
> +{
> +	GLfloat yi;
> +
> +	switch (transition) {
> +	case PATH_TRANSITION_IN_TO_IN:
> +		clip_append_vertex(ctx, x, y);
> +		break;
> +	case PATH_TRANSITION_IN_TO_OUT:
> +		yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
> +		clip_append_vertex(ctx, clip_x, yi);
> +		break;
> +	case PATH_TRANSITION_OUT_TO_IN:
> +		yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
> +		clip_append_vertex(ctx, clip_x, yi);
> +		clip_append_vertex(ctx, x, y);
> +		break;
> +	case PATH_TRANSITION_OUT_TO_OUT:
> +		/* nothing */
> +		break;
> +	default:
> +		assert(0 && "bad enum path_transition");
> +	}
> +
> +	ctx->prev.x = x;
> +	ctx->prev.y = y;
> +}
> +
> +static void
> +clip_polygon_topbottom(struct clip_context *ctx,
> +		       enum path_transition transition,
> +		       GLfloat x, GLfloat y, GLfloat clip_y)
> +{
> +	GLfloat xi;
> +
> +	switch (transition) {
> +	case PATH_TRANSITION_IN_TO_IN:
> +		clip_append_vertex(ctx, x, y);
> +		break;
> +	case PATH_TRANSITION_IN_TO_OUT:
> +		xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
> +		clip_append_vertex(ctx, xi, clip_y);
> +		break;
> +	case PATH_TRANSITION_OUT_TO_IN:
> +		xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
> +		clip_append_vertex(ctx, xi, clip_y);
> +		clip_append_vertex(ctx, x, y);
> +		break;
> +	case PATH_TRANSITION_OUT_TO_OUT:
> +		/* nothing */
> +		break;
> +	default:
> +		assert(0 && "bad enum path_transition");
> +	}
> +
> +	ctx->prev.x = x;
> +	ctx->prev.y = y;
> +}
> +
> +static void
> +clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
> +		      GLfloat *dst_x, GLfloat *dst_y)
> +{
> +	ctx->prev.x = src->x[src->n - 1];
> +	ctx->prev.y = src->y[src->n - 1];
> +	ctx->vertices.x = dst_x;
> +	ctx->vertices.y = dst_y;
> +}
> +
> +static int
> +clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
> +		  GLfloat *dst_x, GLfloat *dst_y)
> +{
> +	enum path_transition trans;
> +	int i;
> +
> +	clip_context_prepare(ctx, src, dst_x, dst_y);
> +	for (i = 0; i < src->n; i++) {
> +		trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
> +		clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
> +				       ctx->clip.x1);
> +	}
> +	return ctx->vertices.x - dst_x;
> +}
> +
> +static int
> +clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
> +		   GLfloat *dst_x, GLfloat *dst_y)
> +{
> +	enum path_transition trans;
> +	int i;
> +
> +	clip_context_prepare(ctx, src, dst_x, dst_y);
> +	for (i = 0; i < src->n; i++) {
> +		trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
> +		clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
> +				       ctx->clip.x2);
> +	}
> +	return ctx->vertices.x - dst_x;
> +}
> +
> +static int
> +clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
> +		 GLfloat *dst_x, GLfloat *dst_y)
> +{
> +	enum path_transition trans;
> +	int i;
> +
> +	clip_context_prepare(ctx, src, dst_x, dst_y);
> +	for (i = 0; i < src->n; i++) {
> +		trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
> +		clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
> +				       ctx->clip.y1);
> +	}
> +	return ctx->vertices.x - dst_x;
> +}
> +
> +static int
> +clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
> +		    GLfloat *dst_x, GLfloat *dst_y)
> +{
> +	enum path_transition trans;
> +	int i;
> +
> +	clip_context_prepare(ctx, src, dst_x, dst_y);
> +	for (i = 0; i < src->n; i++) {
> +		trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
> +		clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
> +				       ctx->clip.y2);
> +	}
> +	return ctx->vertices.x - dst_x;
> +}
> +
> +#define max(a, b) (((a) > (b)) ? (a) : (b))
> +#define min(a, b) (((a) > (b)) ? (b) : (a))
> +#define clip(x, a, b)  min(max(x, a), b)
> +
> +static int
> +calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
> +		pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
> +{
> +	struct polygon8 polygon;
> +	struct clip_context ctx;
> +	int i, n = 0;
> +	GLfloat min_x, max_x, min_y, max_y;
> +	struct polygon8 surf = {
> +		{ surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
> +		{ surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
> +		4
> +	};
> +
> +	ctx.clip.x1 = rect->x1;
> +	ctx.clip.y1 = rect->y1;
> +	ctx.clip.x2 = rect->x2;
> +	ctx.clip.y2 = rect->y2;
> +
> +	/* transform surface to screen space: */
> +	for (i = 0; i < surf.n; i++)
> +		weston_surface_to_global_float(es, surf.x[i], surf.y[i],
> +					       &surf.x[i], &surf.y[i]);
> +
> +	/* find bounding box: */
> +	min_x = max_x = surf.x[0];
> +	min_y = max_y = surf.y[0];
> +
> +	for (i = 1; i < surf.n; i++) {
> +		min_x = min(min_x, surf.x[i]);
> +		max_x = max(max_x, surf.x[i]);
> +		min_y = min(min_y, surf.y[i]);
> +		max_y = max(max_y, surf.y[i]);
> +	}
> +
> +	/* First, simple bounding box check to discard early transformed
> +	 * surface rects that do not intersect with the clip region:
> +	 */
> +	if ((min_x > ctx.clip.x2) || (max_x < ctx.clip.x1) ||
> +	    (min_y > ctx.clip.y2) || (max_y < ctx.clip.y1))
> +		return 0;
> +
> +	/* Simple case, bounding box edges are parallel to surface edges,
> +	 * there will be only four edges.  We just need to clip the surface
> +	 * vertices to the clip rect bounds:
> +	 */
> +	if (!es->transform.enabled) {
> +		for (i = 0; i < surf.n; i++) {
> +			ex[n] = clip(surf.x[i], ctx.clip.x1, ctx.clip.x2);
> +			ey[n] = clip(surf.y[i], ctx.clip.y1, ctx.clip.y2);
> +			n++;
> +		}
> +		return surf.n;
> +	}
> +
> +	/* Transformed case: use a general polygon clipping algorithm to
> +	 * clip the surface rectangle with each side of 'rect'.
> +	 * The algorithm is Sutherland-Hodgman, as explained in
> +	 * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
> +	 * but without looking at any of that code.
> +	 */
> +	polygon.n = clip_polygon_left(&ctx, &surf, polygon.x, polygon.y);
> +	surf.n = clip_polygon_right(&ctx, &polygon, surf.x, surf.y);
> +	polygon.n = clip_polygon_top(&ctx, &surf, polygon.x, polygon.y);
> +	return clip_polygon_bottom(&ctx, &polygon, ex, ey);
> +}
> +
> +
> +/* ---------------------- copied ends -----------------------*/
> +
> +static void
> +geometry_set_phi(struct geometry *g, float phi)
> +{
> +	g->phi = phi;
> +	g->s = sin(phi);
> +	g->c = cos(phi);
> +}
> +
> +static void
> +geometry_init(struct geometry *g)
> +{
> +	g->clip.x1 = -50;
> +	g->clip.y1 = -50;
> +	g->clip.x2 = -10;
> +	g->clip.y2 = -10;
> +
> +	g->surf.x1 = -20;
> +	g->surf.y1 = -20;
> +	g->surf.x2 = 20;
> +	g->surf.y2 = 20;
> +
> +	geometry_set_phi(g, 0.0);
> +}
> +
> +struct ui_state {
> +	uint32_t button;
> +	int down;
> +
> +	int down_pos[2];
> +	struct geometry geometry;
> +};
> +
> +struct cliptest {
> +	struct window *window;
> +	struct widget *widget;
> +	struct display *display;
> +	int fullscreen;
> +
> +	struct ui_state ui;
> +
> +	struct geometry geometry;
> +	struct weston_surface surface;
> +};
> +
> +static void
> +draw_polygon_closed(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
> +{
> +	int i;
> +
> +	cairo_move_to(cr, x[0], y[0]);
> +	for (i = 1; i < n; i++)
> +		cairo_line_to(cr, x[i], y[i]);
> +	cairo_line_to(cr, x[0], y[0]);
> +}
> +
> +static void
> +draw_polygon_labels(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
> +{
> +	char str[16];
> +	int i;
> +
> +	for (i = 0; i < n; i++) {
> +		snprintf(str, 16, "%d", i);
> +		cairo_move_to(cr, x[i], y[i]);
> +		cairo_show_text(cr, str);
> +	}
> +}
> +
> +static void
> +draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_surface *surface)
> +{
> +	GLfloat x[4], y[4];
> +
> +	if (surface) {
> +		weston_surface_to_global_float(surface, box->x1, box->y1, &x[0], &y[0]);
> +		weston_surface_to_global_float(surface, box->x2, box->y1, &x[1], &y[1]);
> +		weston_surface_to_global_float(surface, box->x2, box->y2, &x[2], &y[2]);
> +		weston_surface_to_global_float(surface, box->x1, box->y2, &x[3], &y[3]);
> +	} else {
> +		x[0] = box->x1; y[0] = box->y1;
> +		x[1] = box->x2; y[1] = box->y1;
> +		x[2] = box->x2; y[2] = box->y2;
> +		x[3] = box->x1; y[3] = box->y2;
> +	}
> +
> +	draw_polygon_closed(cr, x, y, 4);
> +}
> +
> +static void
> +draw_geometry(cairo_t *cr, struct weston_surface *surface)
> +{
> +	struct geometry *g = surface->geometry;
> +	GLfloat cx, cy;
> +	GLfloat ex[8], ey[8];
> +	int n;
> +
> +	draw_box(cr, &g->surf, surface);
> +	cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
> +	cairo_fill(cr);
> +	weston_surface_to_global_float(surface, g->surf.x1 - 4, g->surf.y1 - 4, &cx, &cy);
> +	cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI);
> +	if (surface->transform.enabled == 0)
> +		cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8);
> +	cairo_fill(cr);
> +
> +	draw_box(cr, &g->clip, NULL);
> +	cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
> +	cairo_fill(cr);
> +
> +	n = calculate_edges(surface, &g->clip, &g->surf, ex, ey);
> +	draw_polygon_closed(cr, ex, ey, n);
> +	cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
> +	cairo_stroke(cr);
> +
> +	cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
> +	draw_polygon_labels(cr, ex, ey, n);
> +}
> +
> +static void
> +redraw_handler(struct widget *widget, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +	struct rectangle allocation;
> +	cairo_t *cr;
> +	cairo_surface_t *surface;
> +
> +	widget_get_allocation(cliptest->widget, &allocation);
> +
> +	surface = window_get_surface(cliptest->window);
> +	cr = cairo_create(surface);
> +	widget_get_allocation(cliptest->widget, &allocation);
> +	cairo_rectangle(cr, allocation.x, allocation.y,
> +			allocation.width, allocation.height);
> +	cairo_clip(cr);
> +	cairo_push_group(cr);
> +	cairo_translate(cr, allocation.x + allocation.width / 2.0,
> +			allocation.y + allocation.height / 2.0);
> +	cairo_scale(cr, 4.0, 4.0);
> +
> +	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> +	cairo_set_source_rgba(cr, 0, 0, 0, 1);
> +	cairo_paint(cr);
> +
> +	cairo_set_line_width(cr, 0.25);
> +	cairo_move_to(cr, -allocation.width / 2.0, 0.0);
> +	cairo_line_to(cr, allocation.width / 2.0, 0.0);
> +	cairo_move_to(cr, 0.0, -allocation.height / 2.0);
> +	cairo_line_to(cr, 0.0, allocation.height / 2.0);
> +	cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0);
> +	cairo_stroke(cr);
> +
> +	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
> +	cairo_set_line_width(cr, 0.5);
> +	cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
> +	cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
> +			       CAIRO_FONT_WEIGHT_BOLD);
> +	cairo_set_font_size(cr, 5.0);
> +	draw_geometry(cr, &cliptest->surface);
> +
> +	cairo_pop_group_to_source(cr);
> +	cairo_paint(cr);
> +	cairo_destroy(cr);
> +
> +	cairo_surface_destroy(surface);
> +}
> +
> +static int
> +motion_handler(struct widget *widget, struct input *input,
> +	       uint32_t time, float x, float y, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +	struct ui_state *ui = &cliptest->ui;
> +	struct geometry *ref = &ui->geometry;
> +	struct geometry *geom = &cliptest->geometry;
> +	float dx, dy;
> +
> +	if (!ui->down)
> +		return CURSOR_LEFT_PTR;
> +
> +	dx = (x - ui->down_pos[0]) * 0.25;
> +	dy = (y - ui->down_pos[1]) * 0.25;
> +
> +	switch (ui->button) {
> +	case BTN_LEFT:
> +		geom->clip.x1 = ref->clip.x1 + dx;
> +		geom->clip.y1 = ref->clip.y1 + dy;
> +		/* fall through */
> +	case BTN_RIGHT:
> +		geom->clip.x2 = ref->clip.x2 + dx;
> +		geom->clip.y2 = ref->clip.y2 + dy;
> +		break;
> +	default:
> +		return CURSOR_LEFT_PTR;
> +	}
> +
> +	widget_schedule_redraw(cliptest->widget);
> +	return CURSOR_BLANK;
> +}
> +
> +static void
> +button_handler(struct widget *widget, struct input *input,
> +	       uint32_t time, uint32_t button,
> +	       enum wl_pointer_button_state state, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +	struct ui_state *ui = &cliptest->ui;
> +
> +	ui->button = button;
> +
> +	if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
> +		ui->down = 1;
> +		input_get_position(input, &ui->down_pos[0], &ui->down_pos[1]);
> +	} else {
> +		ui->down = 0;
> +		ui->geometry = cliptest->geometry;
> +	}
> +}
> +
> +static void
> +axis_handler(struct widget *widget, struct input *input, uint32_t time,
> +	     uint32_t axis, wl_fixed_t value, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +	struct geometry *geom = &cliptest->geometry;
> +
> +	if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
> +		return;
> +
> +	geometry_set_phi(geom, geom->phi +
> +				(M_PI / 12.0) * wl_fixed_to_double(value));
> +	cliptest->surface.transform.enabled = 1;
> +
> +	widget_schedule_redraw(cliptest->widget);
> +}
> +
> +static void
> +key_handler(struct window *window, struct input *input, uint32_t time,
> +	    uint32_t key, uint32_t sym,
> +	    enum wl_keyboard_key_state state, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +	struct geometry *g = &cliptest->geometry;
> +
> +	if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
> +		return;
> +
> +	switch (sym) {
> +	case XKB_KEY_Escape:
> +		display_exit(cliptest->display);
> +		return;
> +	case XKB_KEY_w:
> +		g->clip.y1 -= 1;
> +		g->clip.y2 -= 1;
> +		break;
> +	case XKB_KEY_a:
> +		g->clip.x1 -= 1;
> +		g->clip.x2 -= 1;
> +		break;
> +	case XKB_KEY_s:
> +		g->clip.y1 += 1;
> +		g->clip.y2 += 1;
> +		break;
> +	case XKB_KEY_d:
> +		g->clip.x1 += 1;
> +		g->clip.x2 += 1;
> +		break;
> +	case XKB_KEY_i:
> +		g->clip.y2 -= 1;
> +		break;
> +	case XKB_KEY_j:
> +		g->clip.x2 -= 1;
> +		break;
> +	case XKB_KEY_k:
> +		g->clip.y2 += 1;
> +		break;
> +	case XKB_KEY_l:
> +		g->clip.x2 += 1;
> +		break;
> +	case XKB_KEY_n:
> +		geometry_set_phi(g, g->phi + (M_PI / 24.0));
> +		cliptest->surface.transform.enabled = 1;
> +		break;
> +	case XKB_KEY_m:
> +		geometry_set_phi(g, g->phi - (M_PI / 24.0));
> +		cliptest->surface.transform.enabled = 1;
> +		break;
> +	case XKB_KEY_r:
> +		geometry_set_phi(g, 0.0);
> +		cliptest->surface.transform.enabled = 0;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	widget_schedule_redraw(cliptest->widget);
> +}
> +
> +static void
> +keyboard_focus_handler(struct window *window,
> +		       struct input *device, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +
> +	window_schedule_redraw(cliptest->window);
> +}
> +
> +static void
> +fullscreen_handler(struct window *window, void *data)
> +{
> +	struct cliptest *cliptest = data;
> +
> +	cliptest->fullscreen ^= 1;
> +	window_set_fullscreen(window, cliptest->fullscreen);
> +}
> +
> +static struct cliptest *
> +cliptest_create(struct display *display)
> +{
> +	struct cliptest *cliptest;
> +
> +	cliptest = malloc(sizeof *cliptest);
> +	if (cliptest == NULL)
> +		return cliptest;
> +	memset(cliptest, 0, sizeof *cliptest);
> +
> +	cliptest->surface.geometry = &cliptest->geometry;
> +	cliptest->surface.transform.enabled = 0;
> +	geometry_init(&cliptest->geometry);
> +	geometry_init(&cliptest->ui.geometry);
> +
> +	cliptest->window = window_create(display);
> +	cliptest->widget = frame_create(cliptest->window, cliptest);
> +	window_set_title(cliptest->window, "cliptest");
> +	cliptest->display = display;
> +
> +	window_set_user_data(cliptest->window, cliptest);
> +	widget_set_redraw_handler(cliptest->widget, redraw_handler);
> +	widget_set_button_handler(cliptest->widget, button_handler);
> +	widget_set_motion_handler(cliptest->widget, motion_handler);
> +	widget_set_axis_handler(cliptest->widget, axis_handler);
> +
> +	window_set_keyboard_focus_handler(cliptest->window,
> +					  keyboard_focus_handler);
> +	window_set_key_handler(cliptest->window, key_handler);
> +	window_set_fullscreen_handler(cliptest->window, fullscreen_handler);
> +
> +	/* set minimum size */
> +	widget_schedule_resize(cliptest->widget, 200, 100);
> +
> +	/* set current size */
> +	widget_schedule_resize(cliptest->widget, 500, 400);
> +
> +	return cliptest;
> +}
> +
> +static struct timespec begin_time;
> +
> +static void
> +reset_timer(void)
> +{
> +	clock_gettime(CLOCK_MONOTONIC, &begin_time);
> +}
> +
> +static double
> +read_timer(void)
> +{
> +	struct timespec t;
> +
> +	clock_gettime(CLOCK_MONOTONIC, &t);
> +	return (double)(t.tv_sec - begin_time.tv_sec) +
> +	       1e-9 * (t.tv_nsec - begin_time.tv_nsec);
> +}
> +
> +static int
> +benchmark(void)
> +{
> +	struct weston_surface surface;
> +	struct geometry geom;
> +	GLfloat ex[8], ey[8];
> +	int i;
> +	double t;
> +	const int N = 1000000;
> +
> +	geom.clip.x1 = -19;
> +	geom.clip.y1 = -19;
> +	geom.clip.x2 = 19;
> +	geom.clip.y2 = 19;
> +
> +	geom.surf.x1 = -20;
> +	geom.surf.y1 = -20;
> +	geom.surf.x2 = 20;
> +	geom.surf.y2 = 20;
> +
> +	geometry_set_phi(&geom, 0.0);
> +
> +	surface.transform.enabled = 1;
> +	surface.geometry = &geom;
> +
> +	reset_timer();
> +	for (i = 0; i < N; i++) {
> +		geometry_set_phi(&geom, (float)i / 360.0f);
> +		calculate_edges(&surface, &geom.clip, &geom.surf, ex, ey);
> +	}
> +	t = read_timer();
> +
> +	printf("%d calls took %g s, average %g us/call\n", N, t, t / N * 1e6);
> +
> +	return 0;
> +}
> +
> +int
> +main(int argc, char *argv[])
> +{
> +	struct display *d;
> +	struct cliptest *cliptest;
> +
> +	if (argc > 1)
> +		return benchmark();
> +
> +	d = display_create(argc, argv);
> +	if (d == NULL) {
> +		fprintf(stderr, "failed to create display: %m\n");
> +		return -1;
> +	}
> +
> +	cliptest = cliptest_create(d);
> +	display_run(d);
> +
> +	widget_destroy(cliptest->widget);
> +	window_destroy(cliptest->window);
> +	free(cliptest);
> +
> +	return 0;
> +}

-------------- next part --------------
A non-text attachment was scrubbed...
Name: wayland-screenshot1.png
Type: image/png
Size: 184411 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20120906/006412bd/attachment-0001.png>


More information about the wayland-devel mailing list