[PATCH weston 03/11] Prepare smoke for multitouch support

Daniel Stone daniel at fooishbar.org
Tue Nov 6 22:51:37 PST 2012


Split motion tracking out into separate handlers so we can have one per
touch.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
 clients/smoke.c |  155 +++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 110 insertions(+), 45 deletions(-)

diff --git a/clients/smoke.c b/clients/smoke.c
index 80b8c58..42540d0 100644
--- a/clients/smoke.c
+++ b/clients/smoke.c
@@ -37,9 +37,18 @@ struct smoke {
 	struct window *window;
 	struct widget *widget;
 	int width, height;
-	int current;
 	uint32_t time;
+	struct wl_list motion_list;
+};
+
+struct motion {
+	struct smoke *smoke;
+	int is_pointer;
+	uint32_t touch_id;
+	int current;
+	int active;
 	struct { float *d, *u, *v; } b[2];
+	struct wl_list link;
 };
 
 static void diffuse(struct smoke *smoke, uint32_t time,
@@ -142,12 +151,14 @@ static void project(struct smoke *smoke, uint32_t time,
 	}
 }
 
-static void render(struct smoke *smoke, cairo_surface_t *surface)
+static int render(struct smoke *smoke, struct motion *motion,
+		  cairo_surface_t *surface)
 {
 	unsigned char *dest;
 	int x, y, width, height, stride;
 	float *s;
 	uint32_t *d, c, a;
+	int ret = 0;
 
 	dest = cairo_image_surface_get_data(surface);
 	width = cairo_image_surface_get_width(surface);
@@ -155,7 +166,7 @@ static void render(struct smoke *smoke, cairo_surface_t *surface)
 	stride = cairo_image_surface_get_stride(surface);
 
 	for (y = 1; y < height - 1; y++) {
-		s = smoke->b[smoke->current].d + y * smoke->height;
+		s = motion->b[motion->current].d + y * smoke->height;
 		d = (uint32_t *) (dest + y * stride);
 		for (x = 1; x < width - 1; x++) {
 			c = (int) (s[x] * 800);
@@ -165,8 +176,12 @@ static void render(struct smoke *smoke, cairo_surface_t *surface)
 			if (a < 0x33)
 				a = 0x33;
 			d[x] = (a << 24) | (c << 16) | (c << 8) | c;
+			if (c != 0)
+				ret = 1;
 		}
 	}
+
+	return ret;
 }
 
 static void
@@ -185,60 +200,78 @@ static const struct wl_callback_listener listener = {
 	frame_callback,
 };
 
-static void
-redraw_handler(struct widget *widget, void *data)
+static int
+do_redraw(struct motion *motion, cairo_surface_t *surface)
 {
-	struct smoke *smoke = data;
+	struct smoke *smoke = motion->smoke;
 	uint32_t time = smoke->time;
-	struct wl_callback *callback;
-	cairo_surface_t *surface;
 
-	diffuse(smoke, time / 30, smoke->b[0].u, smoke->b[1].u);
-	diffuse(smoke, time / 30, smoke->b[0].v, smoke->b[1].v);
+	diffuse(smoke, time / 30, motion->b[0].u, motion->b[1].u);
+	diffuse(smoke, time / 30, motion->b[0].v, motion->b[1].v);
 	project(smoke, time / 30,
-		smoke->b[1].u, smoke->b[1].v,
-		smoke->b[0].u, smoke->b[0].v);
+		motion->b[1].u, motion->b[1].v,
+		motion->b[0].u, motion->b[0].v);
 	advect(smoke, time / 30,
-	       smoke->b[1].u, smoke->b[1].v,
-	       smoke->b[1].u, smoke->b[0].u);
+	       motion->b[1].u, motion->b[1].v,
+	       motion->b[1].u, motion->b[0].u);
 	advect(smoke, time / 30,
-	       smoke->b[1].u, smoke->b[1].v,
-	       smoke->b[1].v, smoke->b[0].v);
+	       motion->b[1].u, motion->b[1].v,
+	       motion->b[1].v, motion->b[0].v);
 	project(smoke, time / 30,
-		smoke->b[0].u, smoke->b[0].v,
-		smoke->b[1].u, smoke->b[1].v);
+		motion->b[0].u, motion->b[0].v,
+		motion->b[1].u, motion->b[1].v);
 
-	diffuse(smoke, time / 30, smoke->b[0].d, smoke->b[1].d);
+	diffuse(smoke, time / 30, motion->b[0].d, motion->b[1].d);
 	advect(smoke, time / 30,
-	       smoke->b[0].u, smoke->b[0].v,
-	       smoke->b[1].d, smoke->b[0].d);
+	       motion->b[0].u, motion->b[0].v,
+	       motion->b[1].d, motion->b[0].d);
 
-	surface = window_get_surface(smoke->window);
+	return render(smoke, motion, surface);
+}
 
-	render(smoke, surface);
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+	struct wl_callback *callback;
+	struct smoke *smoke = data;
+	struct motion *motion, *tmp;
+	cairo_surface_t *surface = window_get_surface(smoke->window);
+	int did_redraw = 0;
+
+	wl_list_for_each_safe(motion, tmp, &smoke->motion_list, link) {
+		if (do_redraw(motion, surface)) {
+			did_redraw = 1;
+			continue;
+		}
 
-	window_damage(smoke->window, 0, 0, smoke->width, smoke->height);
+		if (motion->active == 0) {
+			wl_list_remove(&motion->link);
+			free(motion);
+		}
+	}
 
 	cairo_surface_destroy(surface);
 
+	if (!did_redraw)
+		return;
+
+	window_damage(smoke->window, 0, 0, smoke->width, smoke->height);
 	callback = wl_surface_frame(window_get_wl_surface(smoke->window));
 	wl_callback_add_listener(callback, &listener, smoke);
 	wl_surface_commit(window_get_wl_surface(smoke->window));
 }
 
-static int
-smoke_motion_handler(struct widget *widget, struct input *input,
-		     uint32_t time, float x, float y, void *data)
+static void
+handle_motion(struct motion *motion, float x, float y)
 {
-	struct smoke *smoke = data;
 	int i, i0, i1, j, j0, j1, k, d = 5;
 
 	if (x - d < 1)
 		i0 = 1;
 	else
 		i0 = x - d;
-	if (i0 + 2 * d > smoke->width - 1)
-		i1 = smoke->width - 1;
+	if (i0 + 2 * d > motion->smoke->width - 1)
+		i1 = motion->smoke->width - 1;
 	else
 		i1 = i0 + 2 * d;
 
@@ -246,18 +279,35 @@ smoke_motion_handler(struct widget *widget, struct input *input,
 		j0 = 1;
 	else
 		j0 = y - d;
-	if (j0 + 2 * d > smoke->height - 1)
-		j1 = smoke->height - 1;
+	if (j0 + 2 * d > motion->smoke->height - 1)
+		j1 = motion->smoke->height - 1;
 	else
 		j1 = j0 + 2 * d;
 
 	for (i = i0; i < i1; i++)
 		for (j = j0; j < j1; j++) {
-			k = j * smoke->width + i;
-			smoke->b[0].u[k] += 256 - (random() & 512);
-			smoke->b[0].v[k] += 256 - (random() & 512);
-			smoke->b[0].d[k] += 1;
+			k = j * motion->smoke->width + i;
+			motion->b[0].u[k] += 256 - (random() & 512);
+			motion->b[0].v[k] += 256 - (random() & 512);
+			motion->b[0].d[k] += 1;
+		}
+
+	window_schedule_redraw(motion->smoke->window);
+}
+
+static int
+smoke_motion_handler(struct widget *widget, struct input *input,
+		     uint32_t time, float x, float y, void *data)
+{
+	struct smoke *smoke = data;
+	struct motion *motion;
+
+	wl_list_for_each(motion, &smoke->motion_list, link) {
+		if (motion->is_pointer) {
+			handle_motion(motion, x, y);
+			break;
 		}
+	}
 
 	return CURSOR_HAND1;
 }
@@ -272,12 +322,29 @@ resize_handler(struct widget *widget,
 	widget_set_size(smoke->widget, smoke->width, smoke->height);
 }
 
+static void
+init_motion(struct smoke *smoke, struct motion *motion)
+{
+	int size;
+
+	motion->current = 0;
+	size = smoke->height * smoke->width;
+	motion->b[0].d = calloc(size, sizeof(float));
+	motion->b[0].u = calloc(size, sizeof(float));
+	motion->b[0].v = calloc(size, sizeof(float));
+	motion->b[1].d = calloc(size, sizeof(float));
+	motion->b[1].u = calloc(size, sizeof(float));
+	motion->b[1].v = calloc(size, sizeof(float));
+	motion->smoke = smoke;
+	wl_list_insert(&smoke->motion_list, &motion->link);
+}
+
 int main(int argc, char *argv[])
 {
 	struct timespec ts;
 	struct smoke smoke;
+	struct motion pointer_motion;
 	struct display *d;
-	int size;
 
 	d = display_create(argc, argv);
 	if (d == NULL) {
@@ -290,20 +357,18 @@ int main(int argc, char *argv[])
 	smoke.display = d;
 	smoke.window = window_create(d);
 	smoke.widget = window_add_widget(smoke.window, &smoke);
+	wl_list_init(&smoke.motion_list);
 	window_set_title(smoke.window, "smoke");
 
 	window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM);
 	clock_gettime(CLOCK_MONOTONIC, &ts);
 	srandom(ts.tv_nsec);
 
-	smoke.current = 0;
-	size = smoke.height * smoke.width;
-	smoke.b[0].d = calloc(size, sizeof(float));
-	smoke.b[0].u = calloc(size, sizeof(float));
-	smoke.b[0].v = calloc(size, sizeof(float));
-	smoke.b[1].d = calloc(size, sizeof(float));
-	smoke.b[1].u = calloc(size, sizeof(float));
-	smoke.b[1].v = calloc(size, sizeof(float));
+	wl_list_init(&pointer_motion.link);
+	pointer_motion.is_pointer = 1;
+	pointer_motion.touch_id = 0;
+	pointer_motion.active = 1;
+	init_motion(&smoke, &pointer_motion);
 
 	widget_set_motion_handler(smoke.widget, smoke_motion_handler);
 	widget_set_resize_handler(smoke.widget, resize_handler);
-- 
1.7.10.4



More information about the wayland-devel mailing list