An optical flow driven virtual keyboard.
[vkeyb] / src / vkeyb.cc
1 /* 
2 vkeyb - camera motion detection virtual keyboard
3 Copyright (C) 2012 Eleni Maria Stea <elene.mst@gmail.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <math.h>
21 #include <GL/gl.h>
22 #include <X11/keysym.h>
23 #include <imago2.h>
24 #include "vkeyb.h"
25
26 static KeySym charmap[] = {
27         XK_Greek_ALPHA,
28         XK_Greek_BETA,
29         XK_Greek_GAMMA,
30         XK_Greek_DELTA,
31         XK_Greek_EPSILON,
32         XK_Greek_ZETA,
33         XK_Greek_ETA,
34         XK_Greek_THETA,
35         XK_Greek_IOTA,
36         XK_Greek_KAPPA,
37         XK_Greek_LAMBDA,
38         XK_Greek_MU,
39         XK_Greek_NU,
40         XK_Greek_XI,
41         XK_Greek_OMICRON,
42         XK_Greek_PI,
43         XK_Greek_RHO,
44         XK_Greek_SIGMA,
45         XK_Greek_TAU,
46         XK_Greek_UPSILON,
47         XK_Greek_PHI,
48         XK_Greek_CHI,
49         XK_Greek_PSI,
50         XK_Greek_OMEGA,
51         ' ', '\b', '\n',
52         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
53         'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
54 };
55
56 static unsigned int load_texture(const char *fname);
57
58 VKeyb::VKeyb()
59 {
60         offset = 0;
61         if(!(tex = load_texture("data/glyphs.png"))) {
62                 throw 1;
63         }
64         num_glyphs = 53;
65         visible_glyphs = 24;
66 }
67
68 VKeyb::~VKeyb()
69 {
70         glDeleteTextures(1, &tex);
71 }
72
73 void VKeyb::show() const
74 {
75         float uoffs = floor(offset) / num_glyphs;
76         float umax = (float)visible_glyphs / num_glyphs;
77
78         glEnable(GL_TEXTURE_2D);
79         glBindTexture(GL_TEXTURE_2D, tex);
80
81         glBegin(GL_QUADS);
82         glColor3f(1, 1, 1);
83         glTexCoord2f(uoffs, 1);
84         glVertex2f(-1, -1);
85         glTexCoord2f(uoffs + umax, 1);
86         glVertex2f(1, -1);
87         glTexCoord2f(uoffs + umax, 0);
88         glVertex2f(1, 1);
89         glTexCoord2f(uoffs, 0);
90         glVertex2f(-1, 1);
91         glEnd();
92
93         glDisable(GL_TEXTURE_2D);
94
95         float rect_width = 2.0 / visible_glyphs;
96
97         glLineWidth(2.0);
98         glBegin(GL_LINE_LOOP);
99         glColor3f(1, 0, 0);
100         glVertex2f(0, -1);
101         glVertex2f(rect_width, -1);
102         glVertex2f(rect_width, 1);
103         glVertex2f(0, 1);
104         glEnd();
105 }
106
107 void VKeyb::move(float offs)
108 {
109         float tmp = offset + offs;
110
111         if(tmp < 0.0) {
112                 offset = fmod(num_glyphs + tmp, num_glyphs);
113         } else {
114                 offset = fmod(tmp, num_glyphs);
115         }
116 }
117
118
119 static unsigned int load_texture(const char *fname)
120 {
121         void *pixels;
122         int xsz, ysz;
123         unsigned int tex;
124
125         if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32))) {
126                 fprintf(stderr, "failed to load image: %s\n", fname);
127                 return 0;
128         }
129
130         glGenTextures(1, &tex);
131         glBindTexture(GL_TEXTURE_2D, tex);
132         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
133         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
134         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
135         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
136         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
137
138         if(glGetError() != GL_NO_ERROR) {
139                 img_free_pixels(pixels);
140                 return 0;
141         }
142
143         img_free_pixels(pixels);
144         return tex;
145 }
146
147 int VKeyb::active_glyph() const
148 {
149         return (int)(offset + visible_glyphs / 2) % num_glyphs;
150 }
151
152 KeySym VKeyb::active_key() const
153 {
154         return charmap[active_glyph()];
155 }