blob: df4befb95fb9aaf3df80e03cda170f45008a1543 [file] [log] [blame]
Mathias Agopian37f69342012-02-05 22:25:32 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdint.h>
18#include <sys/types.h>
19
20#include <fcntl.h>
21#include <sys/ioctl.h>
22#include <linux/fb.h>
23#include <linux/input.h>
24#include <errno.h>
25#include <string.h>
26#include <stdio.h>
27#include <cutils/memory.h>
28#include <asm-generic/mman.h>
29#include <sys/mman.h>
30#include <utils/threads.h>
31#include <unistd.h>
32#include <math.h>
33
34using namespace android;
35
36#ifndef FBIO_WAITFORVSYNC
37#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
38#endif
39
40struct Buffer {
41 size_t w;
42 size_t h;
43 size_t s;
44 union {
45 void* addr;
46 uint32_t* pixels;
47 };
48};
49
50void clearBuffer(Buffer* buf, uint32_t pixel) {
51 android_memset32(buf->pixels, pixel, buf->s * buf->h * 4);
52}
53
54void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
55 if (y>0 && y<ssize_t(buf->h)) {
56 uint32_t* bits = buf->pixels + y * buf->s;
57 if (x>=0 && x<buf->w) {
58 bits[x] = pixel;
59 }
60 ssize_t W(w);
61 if ((x+W)>=0 && (x+W)<buf->w) {
62 bits[x+W] = pixel;
63 }
64 }
65}
66
67void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
68 if (y>0 && y<ssize_t(buf->h)) {
69 ssize_t W(w);
70 if (x<0) {
71 W += x;
72 x = 0;
73 }
74 if (x+w > buf->w) {
75 W = buf->w - x;
76 }
77 if (W>0) {
78 uint32_t* bits = buf->pixels + y * buf->s + x;
79 android_memset32(bits, pixel, W*4);
80 }
81 }
82}
83
84void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) {
85 ssize_t W(w), H(h);
86 if (x<0) {
87 w += x;
88 x = 0;
89 }
90 if (y<0) {
91 h += y;
92 y = 0;
93 }
94 if (x+w > buf->w) W = buf->w - x;
95 if (y+h > buf->h) H = buf->h - y;
96 if (W>0 && H>0) {
97 uint32_t* bits = buf->pixels + y * buf->s + x;
98 for (ssize_t i=0 ; i<H ; i++) {
99 android_memset32(bits, pixel, W*4);
100 bits += buf->s;
101 }
102 }
103}
104
105void drawCircle(Buffer* buf, uint32_t pixel,
106 size_t x0, size_t y0, size_t radius, bool filled = false) {
107 ssize_t f = 1 - radius;
108 ssize_t ddF_x = 1;
109 ssize_t ddF_y = -2 * radius;
110 ssize_t x = 0;
111 ssize_t y = radius;
112 if (filled) {
113 drawHLine(buf, pixel, x0-radius, y0, 2*radius);
114 } else {
115 drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius);
116 }
117 while (x < y) {
118 if (f >= 0) {
119 y--;
120 ddF_y += 2;
121 f += ddF_y;
122 }
123 x++;
124 ddF_x += 2;
125 f += ddF_x;
126 if (filled) {
127 drawHLine(buf, pixel, x0-x, y0+y, 2*x);
128 drawHLine(buf, pixel, x0-x, y0-y, 2*x);
129 drawHLine(buf, pixel, x0-y, y0+x, 2*y);
130 drawHLine(buf, pixel, x0-y, y0-x, 2*y);
131 } else {
132 drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x);
133 drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x);
134 drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y);
135 drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y);
136 }
137 }
138}
139
140class TouchEvents {
141 class EventThread : public Thread {
142 int fd;
143
144 virtual bool threadLoop() {
145 input_event event;
146 int first_down = 0;
147 do {
148 read(fd, &event, sizeof(event));
149 if (event.type == EV_ABS) {
150 if (event.code == ABS_MT_TRACKING_ID) {
151 down = event.value == -1 ? 0 : 1;
152 first_down = down;
153 }
154 if (event.code == ABS_MT_POSITION_X) {
155 x = event.value;
156 }
157 if (event.code == ABS_MT_POSITION_Y) {
158 y = event.value;
159 }
160 }
161 } while (event.type == EV_SYN);
162 return true;
163 }
164
165 public:
166 int x, y, down;
167 EventThread() : Thread(false),
168 x(0), y(0), down(0)
169 {
170 fd = open("/dev/input/event1", O_RDONLY);
171 }
172};
173 sp<EventThread> thread;
174
175public:
176 TouchEvents() {
177 thread = new EventThread();
178 thread->run("EventThread", PRIORITY_URGENT_DISPLAY);
179 }
180
181 int getMostRecentPosition(int* x, int* y) {
182 *x = thread->x;
183 *y = thread->y;
184 return thread->down;
185 }
186};
187
188
189struct Queue {
190 struct position {
191 int x, y;
192 };
193 int index;
194 position q[16];
195 Queue() : index(0) { }
196 void push(int x, int y) {
197 index++;
198 index &= 0xF;
199 q[index].x = x;
200 q[index].y = y;
201 }
202 void get(int lag, int* x, int* y) {
203 const int i = (index - lag) & 0xF;
204 *x = q[i].x;
205 *y = q[i].y;
206 }
207};
208
209extern char *optarg;
210extern int optind;
211extern int optopt;
212extern int opterr;
213extern int optreset;
214
215void usage(const char* name) {
216 printf("\nusage: %s [-h] [-l lag]\n", name);
217}
218
219int main(int argc, char** argv) {
220 fb_var_screeninfo vi;
221 fb_fix_screeninfo fi;
222
223 int lag = 0;
224 int fd = open("/dev/graphics/fb0", O_RDWR);
225 ioctl(fd, FBIOGET_VSCREENINFO, &vi);
226 ioctl(fd, FBIOGET_FSCREENINFO, &fi);
227 void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
228 Buffer framebuffer;
229 framebuffer.w = vi.xres;
230 framebuffer.h = vi.yres;
231 framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3);
232 framebuffer.addr = bits;
233
234 int ch;
235 while ((ch = getopt(argc, argv, "hl:")) != -1) {
236 switch (ch) {
237 case 'l':
238 lag = atoi(optarg);
239 break;
240 case 'h':
241 default:
242 usage(argv[0]);
243 exit(0);
244 }
245 }
246 argc -= optind;
247 argv += optind;
248
249
250 TouchEvents touch;
251 Queue queue;
252
253
254 int x=0, y=0, down=0;
255 int lag_x=0, lag_y=0;
256
257 clearBuffer(&framebuffer, 0);
258 while (true) {
259 uint32_t crt = 0;
260 int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt);
261
262 // draw beam marker
263 drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
264 // erase screen
265 if (lag) {
266 drawCircle(&framebuffer, 0, lag_x, lag_y, 100);
267 drawHLine(&framebuffer, 0, 0, lag_y, 32);
268 }
269 drawCircle(&framebuffer, 0, x, y, 100, true);
270 drawHLine(&framebuffer, 0, 0, y, 32);
271
272 // draw a line at y=1000
273 drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w);
274
275 // get touch events
276 touch.getMostRecentPosition(&x, &y);
277 queue.push(x, y);
278 queue.get(lag, &lag_x, &lag_y);
279
280 if (lag) {
281 drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100);
282 drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32);
283 }
284
285 drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true);
286 drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32);
287
288 // draw end of frame beam marker
289 drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h);
290 }
291
292 close(fd);
293 return 0;
294}