summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/grail-frame.c399
-rw-r--r--src/grail-impl.h38
-rw-r--r--src/grail-init.c241
4 files changed, 681 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b26574c..5011c1f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,9 @@ libutouch_grail_la_SOURCES = \
26 grail-event.c \ 26 grail-event.c \
27 grail-impl.h \ 27 grail-impl.h \
28 grail-api.c \ 28 grail-api.c \
29 grail-legacy.c 29 grail-legacy.c \
30 grail-init.c \
31 grail-frame.c
30 32
31# These are flags required to properly set up 33# These are flags required to properly set up
32# the build. -fvisibility requires GCC > 4 (or clang) 34# the build. -fvisibility requires GCC > 4 (or clang)
diff --git a/src/grail-frame.c b/src/grail-frame.c
new file mode 100644
index 0000000..cf38452
--- /dev/null
+++ b/src/grail-frame.c
@@ -0,0 +1,399 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 Canonical Ltd.
6 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23#include "grail-impl.h"
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27
28static void set_center_velocity_and_radius(struct grail_impl *impl,
29 struct grail_element *slot)
30{
31 const struct utouch_contact **tc = slot->touches;
32 double x, y, vx, vy, r2, dx, dy;
33 int i;
34
35 switch (slot->num_touches) {
36 case 1:
37 x = tc[0]->x;
38 y = tc[0]->y;
39 vx = tc[0]->vx;
40 vy = tc[0]->vy;
41 r2 = 0;
42 break;
43 case 2:
44 dx = 0.5 * (tc[1]->x - tc[0]->x);
45 dy = 0.5 * (tc[1]->y - tc[0]->y);
46 x = tc[0]->x + dx;
47 y = tc[0]->y + dy;
48 vx = 0.5 * (tc[0]->vx + tc[1]->vx);
49 vy = 0.5 * (tc[0]->vy + tc[1]->vy);
50 r2 = dx * dx + dy * dy;
51 break;
52 default:
53 x = y = vx = vy = r2 = 0;
54 for (i = 0; i < slot->num_touches; i++) {
55 x += tc[i]->x;
56 y += tc[i]->y;
57 vx += tc[i]->vx;
58 vy += tc[i]->vy;
59 }
60 x /= slot->num_touches;
61 y /= slot->num_touches;
62 vx /= slot->num_touches;
63 vy /= slot->num_touches;
64 for (i = 0; i < slot->num_touches; i++) {
65 dx = tc[i]->x - x;
66 dy = tc[i]->y - y;
67 r2 += dx * dx + dy * dy;
68 }
69 r2 /= slot->num_touches;
70 break;
71 }
72
73 slot->center.x = x;
74 slot->center.y = y;
75 slot->velocity.x = 1000 * vx;
76 slot->velocity.y = 1000 * vy;
77 slot->radius2 = r2;
78}
79
80static void set_moveness_pivot_and_drag(struct grail_impl *impl,
81 struct grail_element *slot,
82 double ds, double dc)
83{
84 const struct grail_control *ctl = impl->ctl;
85 const struct grail_element *pslot = slot->prev;
86 double mx = slot->center.x - pslot->center.x;
87 double my = slot->center.y - pslot->center.y;
88 float *T = slot->transform;
89
90 slot->moveness = 1;
91 slot->pivot = pslot->center;
92
93 if (slot->num_touches > 1) {
94 double wx = (1 - dc) * mx + ds * my;
95 double wy = (1 - dc) * my - ds * mx;
96 double w2 = wx * wx + wy * wy;
97 if (w2 > 0) {
98 double q = (mx * mx + my * my) / w2;
99 double s = ctl->pivot_unbound ?
100 q : sqrt(pslot->radius2 / w2);
101 if (s < q) {
102 slot->moveness = 1 - s / q;
103 slot->pivot.x += s * wx;
104 slot->pivot.y += s * wy;
105 } else {
106 slot->moveness = 0;
107 slot->pivot.x += q * wx;
108 slot->pivot.y += q * wy;
109 }
110 }
111 }
112
113 mx *= slot->moveness;
114 my *= slot->moveness;
115
116 T[0] = dc;
117 T[1] = ds;
118 T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
119 T[3] = -ds;
120 T[4] = dc;
121 T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
122
123 slot->drag.x = pslot->drag.x + mx;
124 slot->drag.y = pslot->drag.y + my;
125}
126
127static void start_slot(struct grail_impl *impl,
128 struct grail_element *slot,
129 const struct utouch_frame *touch)
130{
131 float *T = slot->transform;
132
133 slot->id = impl->seqid++ & GRAIL_ID_MAX;
134 slot->expect_mask = GRAIL_EXPECT_MASK;
135 slot->active_mask = 0;
136 slot->start_time = touch->time;
137 set_center_velocity_and_radius(impl, slot);
138 slot->start_center = slot->center;
139 T[0] = T[4] = 1;
140 T[1] = T[2] = T[3] = T[5] = 0;
141 slot->pivot = slot->center;
142 slot->drag.x = 0;
143 slot->drag.y = 0;
144 slot->scale2 = 1;
145 slot->angle = 0;
146}
147
148static void update_slot(struct grail_impl *impl,
149 struct grail_element *slot,
150 double ds, double dc)
151{
152 const struct grail_element *pslot = slot->prev;
153
154 slot->id = pslot->id;
155 slot->start_time = pslot->start_time;
156 slot->start_center = pslot->start_center;
157 slot->expect_mask = pslot->expect_mask;
158 slot->active_mask = pslot->active_mask;
159
160 set_center_velocity_and_radius(impl, slot);
161 set_moveness_pivot_and_drag(impl, slot, ds, dc);
162
163 slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
164 slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
165}
166
167static void stop_slot(struct grail_impl *impl,
168 struct grail_element *slot)
169{
170 const struct grail_element *pslot = slot->prev;
171 float *T = slot->transform;
172
173 slot->id = -1;
174 slot->num_touches = 0;
175 slot->start_time = pslot->start_time;
176 slot->start_center = pslot->start_center;
177 slot->expect_mask = 0;
178 slot->active_mask = pslot->active_mask;
179 slot->center = pslot->center;
180 slot->velocity = pslot->velocity;
181 slot->radius2 = pslot->radius2;
182 T[0] = T[4] = 1;
183 T[1] = T[2] = T[3] = T[5] = 0;
184 slot->moveness = 1;
185 slot->pivot = pslot->pivot;
186 slot->drag = pslot->drag;
187 slot->scale2 = pslot->scale2;
188 slot->angle = pslot->angle;
189}
190
191static void set_slot_one(struct grail_impl *impl,
192 struct grail_element *slot,
193 const struct utouch_frame *touch,
194 const struct utouch_contact *t1)
195{
196 const struct grail_element *pslot = slot->prev;
197 const struct utouch_contact *p1 = pslot->touches[0];
198
199 if (!t1->active) {
200 stop_slot(impl, slot);
201 return;
202 }
203
204 slot->touches[0] = t1;
205 slot->num_touches = 1;
206
207 if (pslot->num_touches != slot->num_touches || t1->id != p1->id) {
208 start_slot(impl, slot, touch);
209 return;
210 }
211
212 update_slot(impl, slot, 0, 1);
213}
214
215static void set_slot_two(struct grail_impl *impl,
216 struct grail_element *slot,
217 const struct utouch_frame *touch,
218 const struct utouch_contact *t1,
219 const struct utouch_contact *t2)
220{
221 const struct grail_element *pslot = slot->prev;
222 const struct utouch_contact *p1 = pslot->touches[0];
223 const struct utouch_contact *p2 = pslot->touches[1];
224 double tx, ty, px, py, d2;
225
226 if (!t1->active || !t2->active) {
227 stop_slot(impl, slot);
228 return;
229 }
230
231 slot->touches[0] = t1;
232 slot->touches[1] = t2;
233 slot->num_touches = 2;
234
235 if (pslot->num_touches != slot->num_touches ||
236 t1->id != p1->id || t2->id != p2->id) {
237 start_slot(impl, slot, touch);
238 return;
239 }
240
241 tx = t2->x - t1->x;
242 ty = t2->y - t1->y;
243 px = p2->x - p1->x;
244 py = p2->y - p1->y;
245
246 d2 = px * px + py * py;
247 if (d2 > 0) {
248 px /= d2;
249 py /= d2;
250 }
251
252 update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py);
253}
254
255static void set_slot_multi(struct grail_impl *impl,
256 struct grail_element *slot,
257 struct grail_frame *frame,
258 const struct utouch_frame *touch)
259{
260 const struct grail_element *pslot = slot->prev;
261 struct grail_element **slots = frame->slots;
262 int i, j, n = impl->num_touches;
263 struct grail_element *best = 0;
264
265 if (touch->num_active < 3) {
266 stop_slot(impl, slot);
267 return;
268 }
269
270 memcpy(slot->touches, touch->active,
271 touch->num_active * sizeof(slot->touches[0]));
272 slot->num_touches = touch->num_active;
273
274 if (pslot->num_touches != slot->num_touches) {
275 start_slot(impl, slot, touch);
276 return;
277 }
278
279 for (i = 0; i < slot->num_touches; i++) {
280 if (slot->touches[i]->id != pslot->touches[i]->id) {
281 start_slot(impl, slot, touch);
282 return;
283 }
284 }
285
286 for (i = 0; i < impl->num_touches; i++) {
287 for (j = i + 1; j < impl->num_touches; j++) {
288 struct grail_element *s = slots[n++];
289 if (!s->num_touches)
290 continue;
291 if (!best || s->radius2 > best->radius2)
292 best = s;
293 }
294 }
295
296 update_slot(impl, slot, best->transform[1], best->transform[0]);
297}
298
299static void set_slots(struct grail_impl *impl,
300 struct grail_frame *frame,
301 const struct utouch_frame *touch)
302{
303 struct grail_element **slots = frame->slots;
304 struct utouch_contact *const *tc = touch->slots;
305 int i, j, n = 0;
306
307 for (i = 0; i < impl->num_touches; i++)
308 set_slot_one(impl, slots[n++], touch, tc[i]);
309
310 for (i = 0; i < impl->num_touches; i++)
311 for (j = i + 1; j < impl->num_touches; j++)
312 set_slot_two(impl, slots[n++], touch, tc[i], tc[j]);
313
314 set_slot_multi(impl, slots[n++], frame, touch);
315}
316
317static void collect_transforms(struct grail_impl *impl,
318 struct grail_frame *frame,
319 const struct utouch_frame *touch)
320{
321 const struct utouch_surface *s = utouch_frame_get_surface(impl->fh);
322 const struct grail_control *ctl = impl->ctl;
323 float c_x = ctl->bar_center_x * (s->mapped_max_x - s->mapped_min_x);
324 float c_y = ctl->bar_center_y * (s->mapped_max_y - s->mapped_min_y);
325 float d_x = ctl->bar_drag_x * (s->mapped_max_x - s->mapped_min_x);
326 float d_y = ctl->bar_drag_y * (s->mapped_max_y - s->mapped_min_y);
327 float ds2 = ctl->bar_scale * ctl->bar_scale;
328 float dt;
329 int i;
330
331 for (i = 0; i < impl->num_slots; i++) {
332 struct grail_element *s = frame->slots[i];
333
334 if (!s->num_touches)
335 continue;
336
337 dt = touch->time - s->start_time;
338 if (dt > ctl->glue_ms) {
339 unsigned int mask = s->active_mask;
340
341 if (fabs(s->center.x - s->start_center.x) > c_x)
342 mask |= GRAIL_EXPECT_CENTER_X;
343 if (fabs(s->center.y - s->start_center.y) > c_y)
344 mask |= GRAIL_EXPECT_CENTER_Y;
345 if (fabs(s->drag.x) > d_x)
346 mask |= GRAIL_EXPECT_DRAG_X;
347 if (fabs(s->drag.y) > d_y)
348 mask |= GRAIL_EXPECT_DRAG_Y;
349 if (fabs(s->scale2 - 1) > ds2)
350 mask |= GRAIL_EXPECT_SCALE;
351 if (fabs(s->angle) > ctl->bar_angle)
352 mask |= GRAIL_EXPECT_ANGLE;
353
354 s->active_mask = mask;
355
356 if (dt < ctl->drop_x_ms)
357 mask |= GRAIL_EXPECT_CENTER_X;
358 if (dt < ctl->drop_y_ms)
359 mask |= GRAIL_EXPECT_CENTER_Y;
360 if (dt < ctl->drop_x_ms)
361 mask |= GRAIL_EXPECT_DRAG_X;
362 if (dt < ctl->drop_y_ms)
363 mask |= GRAIL_EXPECT_DRAG_Y;
364 if (dt < ctl->drop_scale_ms)
365 mask |= GRAIL_EXPECT_SCALE;
366 if (dt < ctl->drop_angle_ms)
367 mask |= GRAIL_EXPECT_ANGLE;
368
369 s->expect_mask &= mask;
370 }
371
372 frame->ongoing[frame->num_ongoing++] = s;
373 }
374}
375
376const struct grail_frame GRAIL_PUBLIC *
377grail_pump_frame(grail_handle ge, const struct utouch_frame *touch)
378{
379 struct grail_impl *impl = ge->impl;
380 struct grail_frame *frame = impl->frames[impl->nextframe];
381 const struct grail_frame *prev = frame->prev;
382 int i;
383
384 if (touch->slot_revision == touch->prev->slot_revision &&
385 !prev->num_ongoing)
386 return 0;
387
388 frame->touch = touch;
389 frame->num_ongoing = 0;
390 for (i = 0; i < impl->num_slots; i++)
391 frame->slots[i]->prev = prev->slots[i];
392
393 set_slots(impl, frame, touch);
394 collect_transforms(impl, frame, touch);
395
396 impl->nextframe = (impl->nextframe + 1) % impl->num_frames;
397
398 return frame;
399}
diff --git a/src/grail-impl.h b/src/grail-impl.h
index 8f73a2d..e9b1038 100644
--- a/src/grail-impl.h
+++ b/src/grail-impl.h
@@ -33,6 +33,32 @@
33 33
34#define DIM_TOUCH 32 34#define DIM_TOUCH 32
35#define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3) 35#define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3)
36#define GRAIL_ID_MAX 0xffff
37
38#define MIN(a, b) ((a) < (b) ? (a) : (b))
39#define MAX(a, b) ((a) > (b) ? (a) : (b))
40
41typedef void *grail_select_callback;
42
43/*
44 * In this implementation, there can be N one-gestures, N (N - 1) / 2
45 * two-gestures, and one global gesture.
46 */
47static inline int get_slot_count(int n)
48{
49 return n + n * (n - 1) / 2 + 1;
50}
51
52int create_grail2(struct grail_impl *x,
53 utouch_frame_handle fh,
54 unsigned int num_frames,
55 void *select,
56 unsigned int version,
57 unsigned int control_size,
58 unsigned int frame_size,
59 unsigned int slot_size);
60
61void destroy_grail2(struct grail_impl *x);
36 62
37struct grail_impl { 63struct grail_impl {
38 struct evemu_device *evemu; 64 struct evemu_device *evemu;
@@ -45,6 +71,18 @@ struct grail_impl {
45 int ongoing; 71 int ongoing;
46 int gesture; 72 int gesture;
47 FILE *fptest; 73 FILE *fptest;
74 /* new stuff below */
75 struct grail_control *ctl;
76 grail_select_callback select;
77 int num_frames;
78 int num_slots;
79 int num_touches;
80 int nextframe;
81 int seqid;
82 unsigned int control_size;
83 unsigned int frame_size;
84 unsigned int slot_size;
85 struct grail_frame **frames;
48}; 86};
49 87
50#endif 88#endif
diff --git a/src/grail-init.c b/src/grail-init.c
new file mode 100644
index 0000000..18e6996
--- /dev/null
+++ b/src/grail-init.c
@@ -0,0 +1,241 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 Canonical Ltd.
6 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23#include "grail-impl.h"
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27
28static struct grail_control *create_control(int size)
29{
30 struct grail_control *c = calloc(1, size);
31
32 if (!c)
33 return 0;
34
35 c->glue_ms = 60;
36 c->bar_center_x = 0.03;
37 c->bar_center_y = 0.03;
38 c->bar_drag_x = 0.03;
39 c->bar_drag_y = 0.03;
40 c->bar_scale = 0.3;
41 c->bar_angle = 0.1;
42 c->drop_x_ms = 300;
43 c->drop_y_ms = 300;
44 c->drop_scale_ms = 300;
45 c->drop_angle_ms = 300;
46
47 return c;
48}
49
50static void destroy_slots(struct grail_element **slots, int nslot)
51{
52 int i;
53
54 if (slots) {
55 for (i = nslot - 1; i >= 0; i--)
56 free(slots[i]);
57 free(slots);
58 }
59}
60
61static void destroy_frame(struct grail_frame *frame, int nslot)
62{
63 if (frame) {
64 destroy_slots(frame->slots, nslot);
65 free(frame->ongoing);
66 free(frame);
67 }
68}
69
70static void destroy_frames(struct grail_frame **frames, int nframe, int nslot)
71{
72 int i;
73
74 if (frames) {
75 for (i = nframe - 1; i >= 0; i--)
76 destroy_frame(frames[i], nslot);
77 free(frames);
78 }
79}
80
81static struct grail_element **create_slots(int nslot, int ntouch, int size)
82{
83 struct grail_element **slots;
84 struct grail_element *s;
85 int i;
86
87 slots = calloc(nslot, sizeof(slots[0]));
88 if (!slots)
89 return 0;
90
91 for (i = 0; i < nslot; i++) {
92 s = calloc(1, size + ntouch * sizeof(void *));
93 if (!s)
94 goto out;
95 s->slot = i;
96 s->id = -1;
97 s->touches = (void *)((char *)s + size);
98 slots[i] = s;
99 }
100
101 return slots;
102 out:
103 destroy_slots(slots, nslot);
104 return 0;
105}
106
107static struct grail_frame *create_frame(int nslot, int ntouch,
108 int frame_size, int slot_size)
109{
110 struct grail_frame *frame;
111 int i;
112
113 frame = calloc(1, frame_size);
114 if (!frame)
115 return 0;
116
117 frame->ongoing = calloc(nslot, sizeof(frame->ongoing[0]));
118 frame->slots = create_slots(nslot, ntouch, slot_size);
119 if (!frame->ongoing || !frame->slots)
120 goto out;
121
122 return frame;
123 out:
124 destroy_frame(frame, nslot);
125 return 0;
126}
127
128static struct grail_frame **create_frames(int nframe, int nslot, int ntouch,
129 int frame_size, int slot_size)
130{
131 struct grail_frame **frames;
132 struct grail_frame *f;
133 int i;
134
135 frames = calloc(nframe, sizeof(frames[0]));
136 if (!frames)
137 return 0;
138
139 for (i = 0; i < nframe; i++) {
140 f = create_frame(nslot, ntouch, frame_size, slot_size);
141 if (!f)
142 goto out;
143 frames[i] = f;
144 }
145
146 return frames;
147 out:
148 destroy_frames(frames, nframe, nslot);
149 return 0;
150}
151
152int create_grail2(struct grail_impl *x,
153 utouch_frame_handle fh,
154 unsigned int num_frames,
155 grail_select_callback select,
156 unsigned int version,
157 unsigned int control_size,
158 unsigned int frame_size,
159 unsigned int slot_size)
160{
161 struct utouch_surface *s = utouch_frame_get_surface(fh);
162 unsigned int ntouch = utouch_frame_get_num_slots(fh);
163 unsigned int nslot = get_slot_count(ntouch);
164 int i, j;
165
166 x->select = select;
167 x->control_size = MAX(control_size, sizeof(struct grail_control));
168 x->frame_size = MAX(frame_size, sizeof(struct grail_frame));
169 x->slot_size = MAX(slot_size, sizeof(struct grail_element));
170
171 x->num_frames = num_frames;
172 x->num_slots = nslot;
173 x->num_touches = ntouch;
174
175 x->ctl = create_control(x->control_size);
176 if (!x->ctl)
177 goto freemem;
178
179 x->frames = create_frames(num_frames, nslot, ntouch,
180 x->frame_size, x->slot_size);
181 if (!x->frames)
182 goto freemem;
183
184 for (i = 0; i < num_frames; i++)
185 x->frames[(i + 1) % num_frames]->prev = x->frames[i];
186
187 return 0;
188
189 freemem:
190 destroy_grail2(x);
191 return -ENOMEM;
192}
193
194void destroy_grail2(struct grail_impl *x)
195{
196 destroy_frames(x->frames, x->num_frames, x->num_slots);
197 free(x->ctl);
198}
199
200grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh,
201 unsigned int num_frames,
202 grail_select_callback select,
203 unsigned int version,
204 unsigned int control_size,
205 unsigned int frame_size,
206 unsigned int slot_size)
207{
208 struct grail *ge;
209 struct grail_impl *x;
210
211 ge = calloc(1, sizeof(*ge));
212 if (!ge)
213 return 0;
214 x = calloc(1, sizeof(*x));
215 if (!x)
216 goto out;
217 x->fh = fh;
218 if (create_grail2(x, fh, num_frames, select,
219 version, control_size, frame_size, slot_size))
220 goto out;
221
222 ge->impl = x;
223 return ge;
224
225 out:
226 free(x);
227 free(ge);
228 return 0;
229}
230
231void GRAIL_PUBLIC grail_delete(grail_handle ge)
232{
233 destroy_grail2(ge->impl);
234 free(ge->impl);
235 free(ge);
236}
237
238struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge)
239{
240 return ge->impl->ctl;
241}