blob: 778c23cfaec526ea880f16522ca820d8bc38871d [file] [log] [blame]
Rob Bradfordbf33b1c2012-12-03 19:44:15 +00001/*
2 * Copyright © 2012 Intel Corporation
3 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07004 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000010 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070011 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000022 */
23
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010024#include "config.h"
25
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000026#include <stdint.h>
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +020027#include <stdbool.h>
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <cairo.h>
32#include <math.h>
33#include <assert.h>
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +020034#include <getopt.h>
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000035
36#include <linux/input.h>
37#include <wayland-client.h>
38
39#include "window.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070040#include "shared/helpers.h"
Jon Cruz4678bab2015-06-15 15:37:07 -070041#include "shared/matrix.h"
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000042
Rob Bradfordbf33b1c2012-12-03 19:44:15 +000043/* Our points for the calibration must be not be on a line */
44static const struct {
45 float x_ratio, y_ratio;
46} test_ratios[] = {
47 { 0.20, 0.40 },
48 { 0.80, 0.60 },
49 { 0.40, 0.80 }
50};
51
52struct calibrator {
53 struct tests {
54 int32_t drawn_x, drawn_y;
55 int32_t clicked_x, clicked_y;
56 } tests[ARRAY_LENGTH(test_ratios)];
57 int current_test;
58
59 struct display *display;
60 struct window *window;
61 struct widget *widget;
62};
63
64/*
65 * Calibration algorithm:
66 *
67 * The equation we want to apply at event time where x' and y' are the
68 * calibrated co-ordinates.
69 *
70 * x' = Ax + By + C
71 * y' = Dx + Ey + F
72 *
73 * For example "zero calibration" would be A=1.0 B=0.0 C=0.0, D=0.0, E=1.0,
74 * and F=0.0.
75 *
76 * With 6 unknowns we need 6 equations to find the constants:
77 *
78 * x1' = Ax1 + By1 + C
79 * y1' = Dx1 + Ey1 + F
80 * ...
81 * x3' = Ax3 + By3 + C
82 * y3' = Dx3 + Ey3 + F
83 *
84 * In matrix form:
85 *
86 * x1' x1 y1 1 A
87 * x2' = x2 y2 1 x B
88 * x3' x3 y3 1 C
89 *
90 * So making the matrix M we can find the constants with:
91 *
92 * A x1'
93 * B = M^-1 x x2'
94 * C x3'
95 *
96 * (and similarly for D, E and F)
97 *
98 * For the calibration the desired values x, y are the same values at which
99 * we've drawn at.
100 *
101 */
102static void
103finish_calibration (struct calibrator *calibrator)
104{
105 struct weston_matrix m;
106 struct weston_matrix inverse;
107 struct weston_vector x_calib, y_calib;
108 int i;
109
110
111 /*
112 * x1 y1 1 0
113 * x2 y2 1 0
114 * x3 y3 1 0
115 * 0 0 0 1
116 */
117 memset(&m, 0, sizeof(m));
118 for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
119 m.d[i] = calibrator->tests[i].clicked_x;
120 m.d[i + 4] = calibrator->tests[i].clicked_y;
121 m.d[i + 8] = 1;
122 }
123 m.d[15] = 1;
124
125 weston_matrix_invert(&inverse, &m);
126
127 memset(&x_calib, 0, sizeof(x_calib));
128 memset(&y_calib, 0, sizeof(y_calib));
129
130 for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
131 x_calib.f[i] = calibrator->tests[i].drawn_x;
132 y_calib.f[i] = calibrator->tests[i].drawn_y;
133 }
134
135 /* Multiples into the vector */
136 weston_matrix_transform(&inverse, &x_calib);
137 weston_matrix_transform(&inverse, &y_calib);
138
139 printf ("Calibration values: %f %f %f %f %f %f\n",
140 x_calib.f[0], x_calib.f[1], x_calib.f[2],
141 y_calib.f[0], y_calib.f[1], y_calib.f[2]);
142
143 exit(0);
144}
145
146
147static void
148button_handler(struct widget *widget,
149 struct input *input, uint32_t time,
150 uint32_t button,
151 enum wl_pointer_button_state state, void *data)
152{
153 struct calibrator *calibrator = data;
154 int32_t x, y;
155
156 if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
157 input_get_position(input, &x, &y);
158 calibrator->tests[calibrator->current_test].clicked_x = x;
159 calibrator->tests[calibrator->current_test].clicked_y = y;
160
161 calibrator->current_test--;
162 if (calibrator->current_test < 0)
163 finish_calibration(calibrator);
164 }
165
166 widget_schedule_redraw(widget);
167}
168
169static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700170touch_handler(struct widget *widget, struct input *input, uint32_t serial,
171 uint32_t time, int32_t id, float x, float y, void *data)
Rusty Lynch3ba12632013-08-08 21:24:19 -0700172{
173 struct calibrator *calibrator = data;
174
175 calibrator->tests[calibrator->current_test].clicked_x = x;
176 calibrator->tests[calibrator->current_test].clicked_y = y;
177 calibrator->current_test--;
178
179 if (calibrator->current_test < 0)
180 finish_calibration(calibrator);
181
182 widget_schedule_redraw(widget);
183}
184
185static void
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000186redraw_handler(struct widget *widget, void *data)
187{
188 struct calibrator *calibrator = data;
189 struct rectangle allocation;
190 cairo_surface_t *surface;
191 cairo_t *cr;
192 int32_t drawn_x, drawn_y;
193
194 widget_get_allocation(calibrator->widget, &allocation);
195 surface = window_get_surface(calibrator->window);
196
197 cr = cairo_create(surface);
198 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
199 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
200 cairo_paint(cr);
201
202 drawn_x = test_ratios[calibrator->current_test].x_ratio * allocation.width;
203 drawn_y = test_ratios[calibrator->current_test].y_ratio * allocation.height;
204
205 calibrator->tests[calibrator->current_test].drawn_x = drawn_x;
206 calibrator->tests[calibrator->current_test].drawn_y = drawn_y;
207
208 cairo_translate(cr, drawn_x, drawn_y);
209 cairo_set_line_width(cr, 2.0);
210 cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
211 cairo_move_to(cr, 0, -10.0);
212 cairo_line_to(cr, 0, 10.0);
213 cairo_stroke(cr);
214 cairo_move_to(cr, -10.0, 0);
215 cairo_line_to(cr, 10.0, 0.0);
216 cairo_stroke(cr);
217
218 cairo_destroy(cr);
219 cairo_surface_destroy(surface);
220}
221
222static struct calibrator *
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200223calibrator_create(struct display *display, bool enable_button)
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000224{
225 struct calibrator *calibrator;
226
227 calibrator = malloc(sizeof *calibrator);
228 if (calibrator == NULL)
229 return NULL;
230
231 calibrator->window = window_create(display);
232 calibrator->widget = window_add_widget(calibrator->window, calibrator);
233 window_set_title(calibrator->window, "Wayland calibrator");
234 calibrator->display = display;
235
236 calibrator->current_test = ARRAY_LENGTH(test_ratios) - 1;
237
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200238 if (enable_button)
239 widget_set_button_handler(calibrator->widget, button_handler);
Rusty Lynch3ba12632013-08-08 21:24:19 -0700240 widget_set_touch_down_handler(calibrator->widget, touch_handler);
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000241 widget_set_redraw_handler(calibrator->widget, redraw_handler);
242
243 window_set_fullscreen(calibrator->window, 1);
244
245 return calibrator;
246}
247
248static void
249calibrator_destroy(struct calibrator *calibrator)
250{
251 widget_destroy(calibrator->widget);
252 window_destroy(calibrator->window);
253 free(calibrator);
254}
255
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200256static void
257help(const char *name)
258{
259 fprintf(stderr, "Usage: %s [args...]\n", name);
260 fprintf(stderr, " -m, --enable-mouse Enable mouse for testing the touchscreen\n");
261 fprintf(stderr, " -h, --help Display this help message\n");
262}
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000263
264int
265main(int argc, char *argv[])
266{
267 struct display *display;
268 struct calibrator *calibrator;
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200269 int c;
270 bool enable_mouse = 0;
271 struct option opts[] = {
272 { "enable-mouse", no_argument, NULL, 'm' },
273 { "help", no_argument, NULL, 'h' },
274 { 0, 0, NULL, 0 }
275 };
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000276
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200277 while ((c = getopt_long(argc, argv, "mh", opts, NULL)) != -1) {
278 switch (c) {
279 case 'm':
280 enable_mouse = 1;
281 break;
282 case 'h':
283 help(argv[0]);
284 exit(EXIT_FAILURE);
285 default:
286 break;
287 }
288 }
289
Kristian Høgsberg4172f662013-02-20 15:27:49 -0500290 display = display_create(&argc, argv);
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000291
292 if (display == NULL) {
293 fprintf(stderr, "failed to create display: %m\n");
294 return -1;
295 }
296
Fabien Lahouderee80bdcd2017-09-07 15:11:58 +0200297 calibrator = calibrator_create(display, enable_mouse);
Rob Bradfordbf33b1c2012-12-03 19:44:15 +0000298
299 if (!calibrator)
300 return -1;
301
302 display_run(display);
303
304 calibrator_destroy(calibrator);
305 display_destroy(display);
306
307 return 0;
308}
309