psx_gpu: bugfix
[pcsx_rearmed.git] / frontend / pl_gun_ts.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2011
3  *
4  * This work is licensed under the terms of any of these licenses
5  * (at your option):
6  *  - GNU GPL, version 2 or later.
7  *  - GNU LGPL, version 2.1 or later.
8  * See the COPYING file in the top-level directory.
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <dlfcn.h>
14 #include <tslib.h>
15 #include "plugin_lib.h"
16 #include "pl_gun_ts.h"
17 #include "menu.h"
18 #include "../plugins/dfinput/main.h"
19
20 static int gun_x, gun_y, gun_in;
21 static int ts_multiplier_x, ts_multiplier_y, ts_offs_x, ts_offs_y;
22 static int (*pts_read)(struct tsdev *dev, struct ts_sample *sample, int nr);
23 static int (*pts_fd)(struct tsdev *dev);
24
25 #define limit(v, min, max) \
26         if (v < min) v = min; \
27         else if (v > max) v = max
28
29 int pl_gun_ts_update_raw(struct tsdev *ts, int *x, int *y, int *p)
30 {
31         struct ts_sample sample;
32         int sx = 0, sy = 0, sp = 0, updated = 0;
33
34         if (ts != NULL) {
35                 while (pts_read(ts, &sample, 1) > 0) {
36                         sx = sample.x;
37                         sy = sample.y;
38                         sp = sample.pressure;
39                         updated = 1;
40                 }
41
42                 if (updated) {
43                         gun_x = (sx - ts_offs_x) * ts_multiplier_x >> 10;
44                         gun_y = (sy - ts_offs_y) * ts_multiplier_y >> 10;
45                         limit(gun_x, 0, 1023);
46                         limit(gun_y, 0, 1023);
47                         if (sp && !(g_opts & OPT_TSGUN_NOTRIGGER))
48                                 gun_in |= GUNIN_TRIGGER;
49                         else
50                                 gun_in &= ~GUNIN_TRIGGER;
51                 }
52         }
53
54         if (updated) {
55                 if (x) *x = sx;
56                 if (y) *y = sy;
57                 if (p) *p = sp;
58                 return 1;
59         }
60
61         return 0;
62 }
63
64 void pl_gun_ts_update(struct tsdev *ts, int *x, int *y, int *in)
65 {
66         pl_gun_ts_update_raw(ts, NULL, NULL, NULL);
67
68         *x = gun_x;
69         *y = gun_y;
70         *in = gun_in | in_state_gun;
71 }
72
73 void pl_set_gun_rect(int x, int y, int w, int h)
74 {
75         ts_offs_x = x;
76         ts_offs_y = y;
77         ts_multiplier_x = (1<<20) / w;
78         ts_multiplier_y = (1<<20) / h;
79 }
80
81 int pl_gun_ts_get_fd(struct tsdev *ts)
82 {
83         if (ts != NULL && pts_fd != NULL)
84                 return pts_fd(ts);
85
86         return -1;
87 }
88
89 struct tsdev *pl_gun_ts_init(void)
90 {
91         struct tsdev *(*pts_open)(const char *dev_name, int nonblock) = NULL;
92         int (*pts_config)(struct tsdev *) = NULL;
93         int (*pts_close)(struct tsdev *) = NULL;
94         const char *tsdevname;
95         struct tsdev *ts;
96         void *ltsh;
97
98         tsdevname = getenv("TSLIB_TSDEVICE");
99         if (tsdevname == NULL)
100                 tsdevname = "/dev/input/touchscreen0";
101
102         // avoid hard dep on tslib
103         ltsh = dlopen("/usr/lib/libts-1.0.so.0", RTLD_NOW|RTLD_GLOBAL);
104         if (ltsh == NULL)
105                 ltsh = dlopen("/usr/lib/libts-0.0.so.0", RTLD_NOW|RTLD_GLOBAL);
106         if (ltsh == NULL)
107                 ltsh = dlopen("/lib/libts-0.0.so.0", RTLD_NOW|RTLD_GLOBAL);
108         if (ltsh == NULL) {
109                 fprintf(stderr, "%s\n", dlerror());
110                 goto fail;
111         }
112
113         pts_open = dlsym(ltsh, "ts_open");
114         pts_config = dlsym(ltsh, "ts_config");
115         pts_read = dlsym(ltsh, "ts_read");
116         pts_fd = dlsym(ltsh, "ts_fd");
117         pts_close = dlsym(ltsh, "ts_close");
118         if (pts_open == NULL || pts_config == NULL || pts_read == NULL
119             || pts_fd == NULL || pts_close == NULL) {
120                 fprintf(stderr, "%s\n", dlerror());
121                 goto fail_dlsym;
122         }
123
124         ts = pts_open(tsdevname, 1);
125         if (ts == NULL)
126                 goto fail_open;
127         if (pts_config(ts) != 0)
128                 goto fail_config;
129
130         // FIXME: we should be able to get this somewhere
131         // the problem is this doesn't always match resolution due to different display modes
132 #ifdef __ARM_ARCH_7A__
133         pl_set_gun_rect(0, 0, 800, 480);
134 #else
135         pl_set_gun_rect(0, 0, 320, 240);
136 #endif
137         return ts;
138
139 fail_config:
140         pts_close(ts);
141 fail_open:
142 fail_dlsym:
143         dlclose(ltsh);
144         ltsh = NULL;
145 fail:
146         fprintf(stderr, "Could not open touchscreen\n");
147         return NULL;
148 }
149