1 /***************************************************************************
2 *
3 * Copyright (c) 2015 Advanced Driver Information Technology.
4 * This code is developed by Advanced Driver Information Technology.
5 * Copyright of Advanced Driver Information Technology, Bosch, and DENSO.
6 * All rights reserved.
7 *
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <math.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <wayland-client-protocol.h>
32 #include "multi-touch-viewer.h"
33
34 #define WINDOW_TITLE "multi_touch_viewer"
35 #define WINDOW_WIDTH 1080
36 #define WINDOW_HEIGHT 1920
37 #define SURFACE_ID 4000
38 #define LAYER_ID 4000
39
40 #ifndef _UNUSED_
41 # define _UNUSED_(x) (void)x
42 #endif
43
44 static const char *gp_vert_shader_text =
45 "uniform mediump float uX; \n"
46 "uniform mediump float uY; \n"
47 "uniform mediump float uWidth; \n"
48 "uniform mediump float uHeight; \n"
49 "uniform vec3 uColor; \n"
50 "attribute vec4 pos; \n"
51 "varying vec4 v_color; \n"
52 "void main() { \n"
53 " mediump vec4 position; \n"
54 " position.xy = vec2(uX + uWidth * pos.x, \n"
55 " uY + uHeight * pos.y); \n"
56 " position.xy = 2.0 * position.xy - 1.0; \n"
57 " position.zw = vec2(0.0, 1.0); \n"
58 " gl_Position = position; \n"
59 " v_color = vec4(uColor, 1.0); \n"
60 "} \n";
61
62 static const char *gp_frag_shader_text =
63 "precision mediump float; \n"
64 "varying vec4 v_color; \n"
65 "void main() { \n"
66 " gl_FragColor = v_color; \n"
67 "} \n";
68
69 static struct touch_event_test_params *gp_test_params = NULL;
70
71 static int g_is_print_log = 0;
72
73 /******************************************************************************/
74
75 static void frame_callback(void *, struct wl_callback *, uint32_t);
76
77 static void
update_touch_point(struct touch_event_test_params * p_params,int ev,float x,float y,int32_t id,uint32_t time)78 update_touch_point(struct touch_event_test_params *p_params, int ev,
79 float x, float y, int32_t id, uint32_t time)
80 {
81 struct touch_point_params *p_point_params;
82 struct event_log elog;
83
84 if (NULL == p_params)
85 {
86 return;
87 }
88
89 wl_list_for_each(p_point_params, &p_params->touch_point_list, link)
90 {
91 if (p_point_params->id != id)
92 continue;
93
94 switch (ev) {
95 case TOUCH_DOWN:
96 case TOUCH_MOTION:
97 p_point_params->display = 1;
98 p_point_params->x = x;
99 p_point_params->y = y;
100 break;
101 case TOUCH_UP:
102 p_point_params->display = 0;
103 break;
104 default:
105 break;
106 }
107 break;
108 }
109
110 if (g_is_print_log)
111 {
112 printf("[%d] %8.2f %8.2f (%s)\n", id, x, y,
113 (ev == TOUCH_MOTION) ? "MOTION":
114 (ev == TOUCH_DOWN) ? "DOWN" : "UP");
115 }
116
117 /* store event log */
118 elog.event = ev;
119 elog.x = x;
120 elog.y = y;
121 elog.id = id;
122 elog.time = time;
123 log_array_add(&p_params->log_array, &elog);
124 }
125
126 /******************************************************************************/
127
128 static void
frame_callback(void * p_data,struct wl_callback * p_cb,uint32_t time)129 frame_callback(void *p_data, struct wl_callback *p_cb, uint32_t time)
130 {
131 _UNUSED_(time);
132
133 WindowScheduleRedraw((struct WaylandEglWindow*)p_data);
134
135 if (NULL != p_cb)
136 wl_callback_destroy(p_cb);
137 }
138
139 static const struct wl_callback_listener frame_listener = {
140 frame_callback
141 };
142
143 static void
touch_handle_down(void * p_data,struct wl_touch * p_touch,uint32_t serial,uint32_t time,struct wl_surface * p_surface,int32_t id,wl_fixed_t x_w,wl_fixed_t y_w)144 touch_handle_down(void *p_data, struct wl_touch *p_touch, uint32_t serial,
145 uint32_t time, struct wl_surface *p_surface, int32_t id,
146 wl_fixed_t x_w, wl_fixed_t y_w)
147 {
148 _UNUSED_(p_touch);
149 _UNUSED_(serial);
150 _UNUSED_(p_surface);
151
152 update_touch_point((struct touch_event_test_params*)p_data,
153 TOUCH_DOWN,
154 (float)wl_fixed_to_double(x_w),
155 (float)wl_fixed_to_double(y_w),
156 id, time);
157 }
158
159 static void
touch_handle_up(void * p_data,struct wl_touch * p_touch,uint32_t serial,uint32_t time,int32_t id)160 touch_handle_up(void *p_data, struct wl_touch *p_touch, uint32_t serial,
161 uint32_t time, int32_t id)
162 {
163 _UNUSED_(p_touch);
164 _UNUSED_(serial);
165
166 update_touch_point((struct touch_event_test_params*)p_data,
167 TOUCH_UP,
168 0,
169 0,
170 id, time);
171 }
172
173 static void
touch_handle_motion(void * p_data,struct wl_touch * p_touch,uint32_t time,int32_t id,wl_fixed_t x_w,wl_fixed_t y_w)174 touch_handle_motion(void *p_data, struct wl_touch *p_touch, uint32_t time,
175 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
176 {
177 _UNUSED_(p_touch);
178
179 update_touch_point((struct touch_event_test_params*)p_data,
180 TOUCH_MOTION,
181 (float)wl_fixed_to_double(x_w),
182 (float)wl_fixed_to_double(y_w),
183 id, time);
184 }
185
186 static void
touch_handle_frame(void * p_data,struct wl_touch * p_touch)187 touch_handle_frame(void *p_data, struct wl_touch *p_touch)
188 {
189 _UNUSED_(p_data);
190 _UNUSED_(p_touch);
191
192 update_touch_point(NULL, TOUCH_FRAME, 0, 0, 0, 0);
193 }
194
195 static void
touch_handle_cancel(void * p_data,struct wl_touch * p_touch)196 touch_handle_cancel(void *p_data, struct wl_touch *p_touch)
197 {
198 _UNUSED_(p_data);
199 _UNUSED_(p_touch);
200
201 update_touch_point(NULL, TOUCH_CANCEL, 0, 0, 0, 0);
202 }
203
204 static void
touch_handle_shape(void * p_data,struct wl_touch * p_touch,int32_t id,wl_fixed_t major,wl_fixed_t minor)205 touch_handle_shape(void *p_data, struct wl_touch *p_touch,
206 int32_t id, wl_fixed_t major, wl_fixed_t minor)
207 {
208 _UNUSED_(p_data);
209 _UNUSED_(p_touch);
210 _UNUSED_(id);
211 _UNUSED_(major);
212 _UNUSED_(minor);
213 }
214
215 static void
touch_handle_orientation(void * p_data,struct wl_touch * p_touch,int32_t id,wl_fixed_t orientation)216 touch_handle_orientation(void *p_data, struct wl_touch *p_touch,
217 int32_t id, wl_fixed_t orientation)
218 {
219 _UNUSED_(p_data);
220 _UNUSED_(p_touch);
221 _UNUSED_(id);
222 _UNUSED_(orientation);
223 }
224
225 static const struct wl_touch_listener touch_listener = {
226 touch_handle_down,
227 touch_handle_up,
228 touch_handle_motion,
229 touch_handle_frame,
230 touch_handle_cancel,
231 touch_handle_shape,
232 touch_handle_orientation
233 };
234
235 static void
seat_capabilities(void * p_data,struct wl_seat * p_seat,uint32_t caps)236 seat_capabilities(void *p_data, struct wl_seat *p_seat, uint32_t caps)
237 {
238 struct touch_event_test_params *p_params =
239 (struct touch_event_test_params*)p_data;
240
241 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !p_params->p_touch)
242 {
243 p_params->p_touch = wl_seat_get_touch(p_seat);
244 wl_touch_add_listener(p_params->p_touch, &touch_listener, p_data);
245 }
246 else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && p_params->p_touch)
247 {
248 wl_touch_destroy(p_params->p_touch);
249 p_params->p_touch = NULL;
250 }
251 }
252
253 static const struct wl_seat_listener seat_listener = {
254 seat_capabilities,
255 NULL /* name: since version 2 */
256 };
257
258 static void
display_global_handler(struct WaylandDisplay * p_display,uint32_t name,const char * p_interface,uint32_t version,void * p_data)259 display_global_handler(struct WaylandDisplay *p_display, uint32_t name,
260 const char *p_interface, uint32_t version, void *p_data)
261 {
262 _UNUSED_(version);
263 struct touch_event_test_params *p_params =
264 (struct touch_event_test_params*)p_data;
265
266 if (0 == strcmp(p_interface, "wl_seat"))
267 {
268 p_params->p_seat = wl_registry_bind(p_display->p_registry,
269 name, &wl_seat_interface, 1);
270 wl_seat_add_listener(p_params->p_seat, &seat_listener, p_data);
271 }
272 }
273
274 /******************************************************************************/
275
276 static void
draw_grid(int direction,GLfloat width,GLfloat height,float step,struct touch_event_test_params * p_params)277 draw_grid(int direction, GLfloat width, GLfloat height, float step,
278 struct touch_event_test_params *p_params)
279 {
280 GLfloat coord = step;
281 GLfloat uX = 0.0f;
282 GLfloat uY = 0.0f;
283 GLfloat dest_width = 0.0f;
284 GLfloat dest_height = 0.0f;
285 GLfloat dest_coord;
286
287 GLfloat vertices[2][2] = {
288 {0.0f, 0.0f},
289 {0.0f, 0.0f}
290 };
291 #if 0
292 GLfloat line_color[3] = {0.25f, 0.28f, 0.80f};
293 #else
294 GLfloat line_color[3] = {0.1, 0.1, 0.1};
295 #endif
296
297 switch (direction)
298 {
299 case 0: /* verticality */
300 vertices[1][1] = 1.0f;
301 dest_coord = width;
302 break;
303 case 1: /* horizontality */
304 vertices[1][0] = 1.0f;
305 dest_coord = height;
306 break;
307 default:
308 return;
309 }
310
311 glLineWidth(2.0f);
312
313 coord = step;
314 while (coord < dest_coord)
315 {
316 if (direction == 0)
317 {
318 uX = coord / width;
319 dest_height = height;
320 }
321 else
322 {
323 uY = 1.0f - coord / height;
324 dest_width = width;
325 }
326
327 glUniform1fv(p_params->gl.loc_x, 1, &uX);
328 glUniform1fv(p_params->gl.loc_y, 1, &uY);
329 glUniform1fv(p_params->gl.loc_w, 1, &dest_width);
330 glUniform1fv(p_params->gl.loc_h, 1, &dest_height);
331 glUniform3fv(p_params->gl.loc_col, 1, line_color);
332
333 glVertexAttribPointer(p_params->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, vertices);
334
335 glDrawArrays(GL_LINES, 0, 2);
336
337 coord += step;
338 }
339 }
340
341 static void
redraw_handler(struct WaylandEglWindow * p_window,void * p_data)342 redraw_handler(struct WaylandEglWindow *p_window, void *p_data)
343 {
344 GLfloat w, h, uX, uY;
345 GLfloat view_width, view_height;
346 GLfloat dest_width, dest_height;
347 struct touch_event_test_params *p_params = (struct touch_event_test_params*)p_data;
348 struct touch_point_params *p_point_params;
349
350 DisplayAcquireWindowSurface(p_window->p_display, p_window);
351
352 view_width = p_window->geometry.width;
353 view_height = p_window->geometry.height;
354
355 glViewport(0, 0, (int)view_width, (int)view_height);
356
357 #if 0
358 glClearColor(0.60, 0.84, 0.91, 1.0);
359 #else
360 glClearColor(0.7, 0.7, 0.7, 1.0);
361 #endif
362 glClear(GL_COLOR_BUFFER_BIT);
363
364 glEnableVertexAttribArray(p_params->gl.pos);
365
366 /* readraw touch areas */
367 draw_grid(0, view_width, view_height, 100.0f, p_params);
368 draw_grid(1, view_width, view_height, 100.0f, p_params);
369
370 /* redraw pointer circles */
371 wl_list_for_each(p_point_params, &p_params->touch_point_list, link)
372 {
373 if (0 == p_point_params->display)
374 continue;
375
376 w = h = p_point_params->r * 2.0;
377
378 uX = (p_point_params->x - p_point_params->r)/ view_width;
379 uY = 1.0f - (p_point_params->y + p_point_params->r) / view_height;
380
381 dest_width = w / view_width;
382 dest_height = h / view_height;
383
384 glUniform1fv(p_params->gl.loc_x, 1, &uX);
385 glUniform1fv(p_params->gl.loc_y, 1, &uY);
386 glUniform1fv(p_params->gl.loc_w, 1, &dest_width);
387 glUniform1fv(p_params->gl.loc_h, 1, &dest_height);
388 glUniform3fv(p_params->gl.loc_col, 1, p_point_params->color);
389
390 glVertexAttribPointer(p_params->gl.pos, 2,
391 GL_FLOAT, GL_FALSE, 0, p_point_params->p_vertices);
392
393 glDrawArrays(GL_TRIANGLE_FAN, 0, p_point_params->n_vtx);
394 }
395
396 glDisableVertexAttribArray(p_params->gl.pos);
397
398 struct wl_callback *p_cb = wl_surface_frame(p_window->p_surface);
399 wl_callback_add_listener(p_cb, &frame_listener, p_window);
400 }
401
402 /******************************************************************************/
403
404 static GLuint
create_shader(const char * p_source,GLenum shader_type)405 create_shader(const char *p_source, GLenum shader_type)
406 {
407 GLuint shader;
408 GLint status;
409
410 shader = glCreateShader(shader_type);
411 assert(shader != 0);
412
413 glShaderSource(shader, 1, (const char**)&p_source, NULL);
414 glCompileShader(shader);
415
416 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
417 if (0 == status)
418 {
419 char gllog[1000];
420 GLsizei len;
421 glGetShaderInfoLog(shader, sizeof(gllog), &len, gllog);
422 LOG_ERROR("Shader Compiling Failed (%s):\n%*s\n",
423 shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", len, gllog);
424 exit(-1);
425 }
426
427 return shader;
428 }
429
430 static void
init_gl(struct touch_event_test_params * p_params)431 init_gl(struct touch_event_test_params *p_params)
432 {
433 GLuint vert, frag;
434 GLuint program;
435 GLint status;
436
437 vert = create_shader(gp_vert_shader_text, GL_VERTEX_SHADER);
438 frag = create_shader(gp_frag_shader_text, GL_FRAGMENT_SHADER);
439
440 program = glCreateProgram();
441 glAttachShader(program, frag);
442 glAttachShader(program, vert);
443 glLinkProgram(program);
444
445 glGetProgramiv(program, GL_LINK_STATUS, &status);
446 if (0 == status)
447 {
448 char gllog[1000];
449 GLsizei len;
450 glGetProgramInfoLog(program, sizeof(gllog), &len, gllog);
451 LOG_ERROR("Shader Linking Failed:\n%*s\n", len, gllog);
452 exit(-1);
453 }
454
455 glUseProgram(program);
456
457 p_params->gl.pos = 0;
458
459 glBindAttribLocation(program, p_params->gl.pos, "pos");
460
461 p_params->gl.loc_x = glGetUniformLocation(program, "uX");
462 p_params->gl.loc_y = glGetUniformLocation(program, "uY");
463 p_params->gl.loc_w = glGetUniformLocation(program, "uWidth");
464 p_params->gl.loc_h = glGetUniformLocation(program, "uHeight");
465 p_params->gl.loc_col = glGetUniformLocation(program, "uColor");
466 }
467
468 #define NUM_OF_TOUCH_POINT_COLOR 5
469
470 static int
setup_point_params(struct touch_event_test_params * p_params)471 setup_point_params(struct touch_event_test_params *p_params)
472 {
473 struct touch_point_params *p_point_params;
474 int i, j;
475 int n_vtx = 13;
476 float rad = 0.0;
477 float cx = 0.5;
478 float cy = 0.5;
479 float step = (float)(M_PI / 6.0);
480 GLfloat colors[NUM_OF_TOUCH_POINT_COLOR][3] = {
481 {1.0f, 0.0f, 0.0f},
482 {0.0f, 1.0f, 0.0f},
483 {0.0f, 0.0f, 1.0f},
484 {1.0f, 0.0f, 1.0f},
485 {1.0f, 1.0f, 0.0f}
486 };
487
488 for (i = 0; i < NUM_OF_TOUCH_POINT_COLOR; ++i)
489 {
490 p_point_params =
491 (struct touch_point_params*)allocate(sizeof *p_point_params, 1);
492 if (NULL == p_point_params)
493 {
494 LOG_ERROR("Memory allocation failed\n");
495 return -1;
496 }
497
498 p_point_params->display = 0;
499 p_point_params->id = i;
500 p_point_params->x = 0.0;
501 p_point_params->y = 0.0;
502 p_point_params->r = 15.0;
503 p_point_params->n_vtx = n_vtx;
504 p_point_params->p_vertices = (GLfloat*)allocate(sizeof(GLfloat) * n_vtx * 2, 0);
505 assert(NULL != p_point_params->p_vertices);
506
507 for (j = 0; j < (n_vtx - 1); ++j)
508 {
509 p_point_params->p_vertices[j*2 ] = cx + (float)(0.5 * cos(rad));
510 p_point_params->p_vertices[j*2+1] = cy + (float)(0.5 * sin(rad));
511 rad += step;
512 }
513 p_point_params->p_vertices[j*2 ] = p_point_params->p_vertices[0];
514 p_point_params->p_vertices[j*2+1] = p_point_params->p_vertices[1];
515
516 int idx = (i % NUM_OF_TOUCH_POINT_COLOR);
517 memcpy(p_point_params->color, colors[idx], sizeof(GLfloat) * 3);
518
519 wl_list_insert(p_params->touch_point_list.prev, &p_point_params->link);
520 }
521
522 return 0;
523 }
524
525 static int
setup_touch_event_test(struct touch_event_test_params * p_params)526 setup_touch_event_test(struct touch_event_test_params *p_params)
527 {
528 if (0 > setup_point_params(p_params))
529 {
530 return -1;
531 }
532
533 init_gl(p_params);
534 return 0;
535 }
536
537 /******************************************************************************/
538
539 static void
signal_handler(int signum)540 signal_handler(int signum)
541 {
542 switch (signum) {
543 case SIGINT:
544 LOG_INFO("Caught SIGINT - Interrupt\n");
545 LOG_INFO("Recieved touch event information:\n");
546 {
547 int n_down = 0, n_up = 0, n_motion = 0;
548 size_t i;
549 for (i = 0; i < gp_test_params->log_array.n_log; ++i)
550 {
551 switch (gp_test_params->log_array.p_logs[i].event)
552 {
553 case TOUCH_DOWN:
554 ++n_down;
555 break;
556 case TOUCH_MOTION:
557 ++n_motion;
558 break;
559 case TOUCH_UP:
560 ++n_up;
561 break;
562 }
563 }
564 LOG_INFO(" - DOWN event %d\n", n_down);
565 LOG_INFO(" - MOTION event %d\n", n_motion);
566 LOG_INFO(" - UP event %d\n", n_up);
567 }
568 break;
569 default:
570 LOG_INFO("Caught unknown signal(%d), exit\n", signum);
571 break;
572 }
573
574 DisplayExit(gp_test_params->p_display);
575 }
576
577 static void
setup_signal()578 setup_signal()
579 {
580 struct sigaction sigact;
581
582 sigact.sa_handler = signal_handler;
583 sigemptyset(&sigact.sa_mask);
584 sigact.sa_flags = 0;
585 sigaction(SIGINT, &sigact, NULL);
586 }
587
588 /******************************************************************************/
589
590 int
touch_event_test_main(struct touch_event_test_params * p_params)591 touch_event_test_main(struct touch_event_test_params *p_params)
592 {
593 struct WaylandDisplay *p_display;
594 struct WaylandEglWindow *p_window;
595
596 setup_signal();
597
598 p_display = CreateDisplay(0, NULL);
599 if (NULL == p_display)
600 {
601 LOG_ERROR("Failed to create display\n");
602 return -1;
603 }
604 p_params->p_display = p_display;
605
606 DisplaySetUserData(p_display, p_params);
607 DisplaySetGlobalHandler(p_display, display_global_handler);
608
609 p_window = CreateEglWindow(p_display, WINDOW_TITLE, SURFACE_ID);
610 if (NULL == p_window)
611 {
612 LOG_ERROR("Failed to create EGL window\n");
613 DestroyDisplay(p_display);
614 return -1;
615 }
616 p_params->p_window = p_window;
617
618 /**
619 * TODO: Create setter function to window.c
620 */
621 p_window->redraw_handler = redraw_handler;
622 p_window->p_user_data = p_params;
623
624 WindowScheduleResize(p_window, WINDOW_WIDTH, WINDOW_HEIGHT);
625 WindowCreateSurface(p_window);
626
627 if (0 > setup_touch_event_test(p_params))
628 {
629 LOG_ERROR("Failed to setup this viewer\n");
630 DestroyDisplay(p_display);
631 return -1;
632 }
633
634 DisplayRun(p_display);
635
636 /* Print event information */
637 LOG_INFO("Number of events: %lu\n", p_params->log_array.n_log);
638
639 log_array_release(&p_params->log_array);
640
641 return 0;
642 }
643
644 void
usage(int status)645 usage(int status)
646 {
647 printf("usage: multi-touch-viewer [OPTION]\n");
648 printf(" -p : print received touch point\n");
649 exit(status);
650 }
651
652 int
main(int argc,char ** argv)653 main(int argc, char **argv)
654 {
655 _UNUSED_(argc);
656 _UNUSED_(argv);
657 struct touch_event_test_params params;
658
659 memset(¶ms, 0x00, sizeof params);
660
661 if (argc == 2)
662 {
663 if (0 == strcmp(argv[1], "-p"))
664 {
665 g_is_print_log = 1;
666 }
667 else
668 {
669 usage(EXIT_SUCCESS);
670 }
671 }
672
673 gp_test_params = ¶ms;
674
675 wl_list_init(¶ms.touch_point_list);
676
677 log_array_init(¶ms.log_array, 500);
678
679 return touch_event_test_main(¶ms);
680 }
681