diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2011-04-28 18:42:33 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2011-04-28 18:42:33 +0200 |
| commit | 5423ccd321c1c84b0e7736b10b2fe9eeb1833e16 (patch) | |
| tree | fc12f236a865dceb6008d9bc5691b0fd0cbe582b /src | |
| parent | d87cde46e25c058ffc76d3871ca4e2ceb3e57991 (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>
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/grail-frame.c | 399 | ||||
| -rw-r--r-- | src/grail-impl.h | 38 | ||||
| -rw-r--r-- | src/grail-init.c | 241 |
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 | |||
| 28 | static 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 | |||
| 80 | static 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 | |||
| 127 | static 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 | |||
| 148 | static 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 | |||
| 167 | static 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 | |||
| 191 | static 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 | |||
| 215 | static 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 | |||
| 255 | static 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 | |||
| 299 | static 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 | |||
| 317 | static 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 | |||
| 376 | const struct grail_frame GRAIL_PUBLIC * | ||
| 377 | grail_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 | |||
| 41 | typedef 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 | */ | ||
| 47 | static inline int get_slot_count(int n) | ||
| 48 | { | ||
| 49 | return n + n * (n - 1) / 2 + 1; | ||
| 50 | } | ||
| 51 | |||
| 52 | int 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 | |||
| 61 | void destroy_grail2(struct grail_impl *x); | ||
| 36 | 62 | ||
| 37 | struct grail_impl { | 63 | struct 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 | |||
| 28 | static 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 | |||
| 50 | static 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 | |||
| 61 | static 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 | |||
| 70 | static 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 | |||
| 81 | static 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 | |||
| 107 | static 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 | |||
| 128 | static 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 | |||
| 152 | int 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 | |||
| 194 | void destroy_grail2(struct grail_impl *x) | ||
| 195 | { | ||
| 196 | destroy_frames(x->frames, x->num_frames, x->num_slots); | ||
| 197 | free(x->ctl); | ||
| 198 | } | ||
| 199 | |||
| 200 | grail_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 | |||
| 231 | void GRAIL_PUBLIC grail_delete(grail_handle ge) | ||
| 232 | { | ||
| 233 | destroy_grail2(ge->impl); | ||
| 234 | free(ge->impl); | ||
| 235 | free(ge); | ||
| 236 | } | ||
| 237 | |||
| 238 | struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge) | ||
| 239 | { | ||
| 240 | return ge->impl->ctl; | ||
| 241 | } | ||
