summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2011-04-28 18:42:33 +0200
committerHenrik Rydberg <rydberg@euromail.se>2011-04-28 18:42:33 +0200
commit5423ccd321c1c84b0e7736b10b2fe9eeb1833e16 (patch)
treefc12f236a865dceb6008d9bc5691b0fd0cbe582b
parentd87cde46e25c058ffc76d3871ca4e2ceb3e57991 (diff)
Introduce gesture frames
This patch extends the API with parallel new/delete functions, aiming to eventually replace the open/close function. The new functions give access to the grail gesture frames, containing gestural transform information. This information is useful in its own right, and will eventually replace the internal recognizer. Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
-rw-r--r--include/grail.h204
-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
5 files changed, 885 insertions, 1 deletions
diff --git a/include/grail.h b/include/grail.h
index b208556..d9f3937 100644
--- a/include/grail.h
+++ b/include/grail.h
@@ -44,8 +44,17 @@ extern "C" {
44#define GRAIL_STATUS_UPDATE 1 44#define GRAIL_STATUS_UPDATE 1
45#define GRAIL_STATUS_END 2 45#define GRAIL_STATUS_END 2
46 46
47#define GRAIL_EXPECT_CENTER_X 0x0001
48#define GRAIL_EXPECT_CENTER_Y 0x0002
49#define GRAIL_EXPECT_DRAG_X 0x0004
50#define GRAIL_EXPECT_DRAG_Y 0x0008
51#define GRAIL_EXPECT_SCALE 0x0010
52#define GRAIL_EXPECT_ANGLE 0x0020
53#define GRAIL_EXPECT_MASK 0x003f
54
47typedef float grail_prop_t; /* gesture properties */ 55typedef float grail_prop_t; /* gesture properties */
48typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */ 56typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */
57typedef struct grail *grail_handle; /* the grail instance handle */
49 58
50/** 59/**
51 * struct grail_get_version - get grail library version 60 * struct grail_get_version - get grail library version
@@ -69,6 +78,64 @@ struct grail_coord {
69 float x, y; 78 float x, y;
70}; 79};
71 80
81grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh,
82 unsigned int num_frames,
83 void *select,
84 unsigned int version,
85 unsigned int control_size,
86 unsigned int frame_size,
87 unsigned int slot_size);
88
89/**
90 * grail_new - allocate and initialize a new grail instance
91 * @fh: utouch frame handle to use
92 * @num_frames: number of frames in cyclic buffer
93 * @select: client selection callback
94 *
95 * Initialize the internal grail structures.
96 *
97 * Returns zero in case of failure.
98 */
99#define grail_new(fh, num_frames, select) \
100 grail_new_raw(fh, num_frames, select, \
101 GRAIL_VERSION, \
102 sizeof(struct grail_control), \
103 sizeof(struct grail_frame), \
104 sizeof(struct grail_element))
105
106/**
107 * grail_delete - destroy and delete grail instance
108 * @ge: grail instance in use
109 *
110 * Deallocates all internal memory structures.
111 */
112void GRAIL_PUBLIC grail_delete(grail_handle ge);
113
114/**
115 * grail_get_control - get mutable control structure
116 * @ge: the grail device in use
117 *
118 * Return the control struct of the grail instance.
119 *
120 * The control pointer is ABI agnostic, owned by the grail instance, and
121 * has grail scope.
122 */
123struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge);
124
125/**
126 * grail_pump_frame - insert touch frames into grail
127 * @ge: the grail device in use
128 * @frame: the touch frame to insert
129 *
130 * Insert a new touch frame into the grail engine. If the frame induces a
131 * new gesture frame, a pointer to the frame is returned.
132 *
133 * The grail frame pointer is ABI agnostic, owned by the grail instance, and
134 * has grail scope.
135 */
136const struct grail_frame GRAIL_PUBLIC *
137grail_pump_frame(grail_handle ge, const struct utouch_frame *frame);
138
72/** 139/**
73 * struct grail_client_id - Gesture client information 140 * struct grail_client_id - Gesture client information
74 * @client: Client id 141 * @client: Client id
@@ -95,6 +162,143 @@ struct grail_client_info {
95}; 162};
96 163
97/** 164/**
165 * struct grail_control - control parameters of grail
166 * @glue_ms: minimum time to hold activation (ms)
167 * @bar_center_x: horizontal distance to activate (surface width fraction)
168 * @bar_center_y: vertical distance to activate (surface height fraction)
169 * @bar_drag_x: horizontal distance to activate (surface width fraction)
170 * @bar_drag_y: vertical distance to activate (surface height fraction)
171 * @bar_scale: minimum scaling to activate (fraction)
172 * @bar_angle: minimum angle to activate (radians)
173 * @drop_x_ms: horizontal expect timeout (ms)
174 * @drop_y_ms: vertical expect timeout (ms)
175 * @drop_scale_ms: scaling expect timeout (ms)
176 * @drop_angle_ms: rotation expect timeout (ms)
177 * @pivot_unbound: when true, the pivot is not bound to the contact area
178 *
179 * The parameters are used to tune the behavior of the gesture recognition.
180 *
181 * The moveness is a number between zero and one denoting the
182 * character of the current transform. Zero means pure rotate and
183 * scale, one means pure drag.
184 *
185 * Later versions of this struct may grow in size, but will remain
186 * binary compatible with older versions.
187 */
188struct grail_control {
189 float glue_ms;
190 float bar_center_x;
191 float bar_center_y;
192 float bar_drag_x;
193 float bar_drag_y;
194 float bar_scale;
195 float bar_angle;
196 float drop_x_ms;
197 float drop_y_ms;
198 float drop_scale_ms;
199 float drop_angle_ms;
200 int pivot_unbound;
201};
202
203/**
204 * struct grail_frame - frame of ongoing elementary transformations
205 * @prev: pointer to the previous gesture frame
206 * @touch: pointer to the touch frame triggering this gesture frame
207 * @num_ongoing: number of elements in the ongoing array
208 * @ongoing: array of ongoing transformation elements
209 * @slots: array of all transformation slots
210 *
211 * A gesture frame consists of one or several touch frames glued
212 * together into a stable transition, combined with information on
213 * ongoing elementary gestural transformations. The array of ongoing
214 * elements contains all elements with a nonzero expect mask.
215 *
216 * Later versions of this struct may grow in size, but will remain
217 * binary compatible with older versions.
218 */
219struct grail_frame {
220 const struct grail_frame *prev;
221 const struct utouch_frame *touch;
222 unsigned int num_ongoing;
223 struct grail_element **ongoing;
224 struct grail_element **slots;
225};
226
227/**
228 * struct grail_element - elementary gesture transformation
229 * @prev: respective element of previous frame
230 * @slot: the transformation slot occupied by this element
231 * @id: unique identifier of the ongoing transformation
232 * @num_touches: number of contacts of this element
233 * @touches: array of contacts of this element
234 * @start_time: start time of this element
235 * @start_center: center position at start of transform (surface units)
236 * @expect_mask: bitmask of expected gestures (grail main types)
237 * @active_mask: bitmask of activated gestures (grail main types)
238 * @center: gesture center position (surface units)
239 * @velocity: current center velocity (surface units per second)
240 * @radius: gesture radius from center (surface units)
241 * @transform: the transformation matrix of the gesture
242 * @pivot: current center of rotate and scale (surface units)
243 * @drag: accumulated transformation displacement (surface units)
244 * @scale: accumulated scale (dimensionless)
245 * @angle: accumulated rotation angle (radians)
246 *
247 * The grail element describes the ongoing gestural transformation of
248 * a particular set of contacts. The expect mask describes which
249 * gestural transformations may become active during the course of
250 * events, and the active mask describes which have passed their
251 * respective activation threshold. The set of expected gestures can
252 * change over time, for instance by exclusion or timeout.
253 *
254 * Applications handling rotation, either by transformation matrix or
255 * angle, should use the drag displacement. For other applications,
256 * the center displacement may be used instead, as to not lose
257 * movement accuracy.
258 *
259 * Later versions of this struct may grow in size, but will remain
260 * binary compatible with older versions.
261 */
262struct grail_element {
263 const struct grail_element *prev;
264 int slot;
265 int id;
266 int num_touches;
267 const struct utouch_contact **touches;
268 grail_time_t start_time;
269 struct grail_coord start_center;
270 unsigned int expect_mask;
271 unsigned int active_mask;
272 struct grail_coord center;
273 struct grail_coord velocity;
274 float radius2;
275 float transform[6];
276 float moveness;
277 struct grail_coord pivot;
278 struct grail_coord drag;
279 float scale2;
280 float angle;
281};
282
283/**
284 * grail_element_transform - transform coordinates using element
285 * @slot: the transformation element to use
286 * @q: the grail coordinate to fill
287 * @x: the grail coordinate to transform
288 *
289 * Performs the 3x3 transform *q = T *p, where T is the element
290 * transform.
291 */
292static inline void grail_element_transform(const struct grail_element *slot,
293 struct grail_coord *q,
294 const struct grail_coord *p)
295{
296 const float *T = slot->transform;
297 q->x = T[0] * p->x + T[1] * p->y + T[2];
298 q->y = T[3] * p->x + T[4] * p->y + T[5];
299}
300
301/**
98 * struct grail_event - Gesture event 302 * struct grail_event - Gesture event
99 * @type: The gesture type 303 * @type: The gesture type
100 * @id: Unique identifier foof the gesture instance 304 * @id: Unique identifier foof the gesture instance
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}