]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/eui.c
demote libemu to common code
[plan9front.git] / sys / src / games / eui.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include <keyboard.h>
6 #include <mouse.h>
7 #include "eui.h"
8
9 typedef struct Kfn Kfn;
10
11 u64int keys, keys2;
12 int trace, paused;
13 int savereq, loadreq;
14 QLock pauselock;
15 int scale, warp10;
16 uchar *pic;
17 Rectangle picr;
18 Mousectl *mc;
19 Image *bg;
20
21 static int profile, framestep;
22 static int vwdx, vwdy, vwbpp;
23 static ulong vwchan;
24 static Image *fb;
25
26 struct Kfn{
27         Rune r;
28         int k;
29         char joyk[16];
30         void(*fn)(void);
31         Kfn *n;
32 };
33 Kfn kfn, kkn;
34
35 void *
36 emalloc(ulong sz)
37 {
38         void *v;
39
40         v = mallocz(sz, 1);
41         if(v == nil)
42                 sysfatal("malloc: %r");
43         setmalloctag(v, getcallerpc(&sz));
44         return v;
45 }
46
47 static void
48 joyproc(void *)
49 {
50         char *s, *down[9];
51         static char buf[64];
52         int n, k, j;
53         Kfn *kp;
54
55         j = 1;
56
57         for(;;){
58                 n = read(0, buf, sizeof(buf) - 1);
59                 if(n <= 0)
60                         sysfatal("read: %r");
61                 buf[n] = 0;
62                 n = getfields(buf, down, nelem(down), 1, " ");
63                 k = 0;
64                 for(n--; n >= 0; n--){
65                         s = down[n];
66                         if(strcmp(s, "joy1") == 0)
67                                 j = 1;
68                         else if(strcmp(s, "joy2") == 0)
69                                 j = 2;
70                         for(kp=kkn.n; kp!=nil; kp=kp->n){
71                                 if(strcmp(kp->joyk, s) == 0)
72                                         k |= kp->k;
73                         }
74                 }
75                 if(j == 2)
76                         keys2 = k;
77                 else
78                         keys = k;
79         }
80 }
81
82 static void
83 keyproc(void *)
84 {
85         int fd, n, k;
86         static char buf[256];
87         char *s;
88         Rune r;
89         Kfn *kp;
90
91         fd = open("/dev/kbd", OREAD);
92         if(fd < 0)
93                 sysfatal("open: %r");
94         for(;;){
95                 if(buf[0] != 0){
96                         n = strlen(buf)+1;
97                         memmove(buf, buf+n, sizeof(buf)-n);
98                 }
99                 if(buf[0] == 0){
100                         n = read(fd, buf, sizeof(buf)-1);
101                         if(n <= 0)
102                                 sysfatal("read /dev/kbd: %r");
103                         buf[n-1] = 0;
104                         buf[n] = 0;
105                 }
106                 if(buf[0] == 'c'){
107                         if(utfrune(buf, Kdel)){
108                                 close(fd);
109                                 threadexitsall(nil);
110                         }
111                         if(utfrune(buf, KF|5))
112                                 savereq = 1;
113                         if(utfrune(buf, KF|6))
114                                 loadreq = 1;
115                         if(utfrune(buf, KF|12))
116                                 profile ^= 1;
117                         if(utfrune(buf, 't'))
118                                 trace = !trace;
119                         for(kp=kfn.n; kp!=nil; kp=kp->n){
120                                 if(utfrune(buf, kp->r))
121                                         kp->fn();
122                         }
123                 }
124                 if(buf[0] != 'k' && buf[0] != 'K')
125                         continue;
126                 s = buf + 1;
127                 k = 0;
128                 while(*s != 0){
129                         s += chartorune(&r, s);
130                         switch(r){
131                         case Kdel: close(fd); threadexitsall(nil);
132                         case Kesc:
133                                 if(paused)
134                                         qunlock(&pauselock);
135                                 else
136                                         qlock(&pauselock);
137                                 paused = !paused;
138                                 break;
139                         case KF|1:      
140                                 if(paused){
141                                         qunlock(&pauselock);
142                                         paused=0;
143                                 }
144                                 framestep = !framestep;
145                                 break;
146                         case '`':
147                                 warp10 = !warp10;
148                                 break;
149                         }
150                         for(kp=kkn.n; kp!=nil; kp=kp->n){
151                                 if(utfrune(buf, kp->r))
152                                         k |= kp->k;
153                         }
154                 }
155                 k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
156                 keys = k;
157         }
158 }
159
160 static void
161 timing(void)
162 {
163         static int fcount;
164         static vlong old;
165         static char buf[32];
166         vlong new;
167
168         if(++fcount == 60)
169                 fcount = 0;
170         else
171                 return;
172         new = nsec();
173         if(new != old)
174                 sprint(buf, "%6.2f%%", 1e11 / (new - old));
175         else
176                 buf[0] = 0;
177         draw(screen, rectaddpt(Rect(10, 10, vwdx-40, 30), screen->r.min), bg, nil, ZP);
178         string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
179         old = nsec();
180 }
181
182 static void
183 screeninit(void)
184 {
185         Point p;
186
187         scale = Dx(screen->r) / vwdx;
188         if(scale <= 0)
189                 scale = 1;
190         else if(scale > 16)
191                 scale = 16;
192         p = divpt(addpt(screen->r.min, screen->r.max), 2);
193         picr = Rpt(subpt(p, Pt(scale * vwdx/2, scale * vwdy/2)),
194                 addpt(p, Pt(scale * vwdx/2, scale * vwdy/2)));
195         freeimage(fb);
196         fb = allocimage(display, Rect(0, 0, scale * vwdx, scale > 1 ? 1 : scale * vwdy),
197                 vwchan, scale > 1, 0);
198         free(pic);
199         pic = emalloc(vwdx * vwdy * vwbpp * scale);
200         draw(screen, screen->r, bg, nil, ZP);   
201 }
202
203 void
204 flushmouse(int discard)
205 {
206         Mouse m;
207
208         if(nbrecvul(mc->resizec) > 0){
209                 if(getwindow(display, Refnone) < 0)
210                         sysfatal("resize failed: %r");
211                 screeninit();
212         }
213         if(discard)
214                 while(nbrecv(mc->c, &m) > 0)
215                         ;
216 }
217
218 void
219 flushscreen(void)
220 {
221         flushmouse(1);
222         if(scale == 1){
223                 loadimage(fb, fb->r, pic, vwdx * vwdy * vwbpp);
224                 draw(screen, picr, fb, nil, ZP);
225         } else {
226                 Rectangle r;
227                 uchar *s;
228                 int w;
229
230                 s = pic;
231                 r = picr;
232                 w = vwdx * vwbpp * scale;
233                 while(r.min.y < picr.max.y){
234                         loadimage(fb, fb->r, s, w);
235                         s += w;
236                         r.max.y = r.min.y+scale;
237                         draw(screen, r, fb, nil, ZP);
238                         r.min.y = r.max.y;
239                 }
240         }
241         flushimage(display, 1);
242         if(profile)
243                 timing();
244 }
245
246 void
247 flushaudio(int (*audioout)(void))
248 {
249         static vlong old, delta;
250         vlong new, diff;
251
252         if(audioout == nil || audioout() < 0 && !warp10){
253                 new = nsec();
254                 diff = 0;
255                 if(old != 0){
256                         diff = BILLION/60 - (new - old) - delta;
257                         if(diff >= MILLION)
258                                 sleep(diff/MILLION);
259                 }
260                 old = nsec();
261                 if(diff > 0){
262                         diff = (old - new) - (diff / MILLION) * MILLION;
263                         delta += (diff - delta) / 100;
264                 }
265         }
266         if(framestep){
267                 paused = 1;
268                 qlock(&pauselock);
269                 framestep = 0;
270         }
271 }
272
273 void
274 regkeyfn(Rune r, void (*fn)(void))
275 {
276         Kfn *kp;
277
278         for(kp=&kfn; kp->n!=nil; kp=kp->n)
279                 ;
280         kp->n = emalloc(sizeof *kp);
281         kp->n->r = r;
282         kp->n->fn = fn;
283 }
284
285 void
286 regkey(char *joyk, Rune r, int k)
287 {
288         Kfn *kp;
289
290         for(kp=&kkn; kp->n!=nil; kp=kp->n)
291                 ;
292         kp->n = emalloc(sizeof *kp);
293         strncpy(kp->n->joyk, joyk, sizeof(kp->n->joyk)-1);
294         kp->n->r = r;
295         kp->n->k = k;
296 }
297
298 void
299 initemu(int dx, int dy, int bpp, ulong chan, int dokey, void(*kproc)(void*))
300 {
301         vwdx = dx;
302         vwdy = dy;
303         vwchan = chan;
304         vwbpp = bpp;
305         if(initdraw(nil, nil, nil) < 0)
306                 sysfatal("initdraw: %r");
307         mc = initmouse(nil, screen);
308         if(mc == nil)
309                 sysfatal("initmouse: %r");
310         if(dokey)
311                 proccreate(kproc != nil ? kproc : keyproc, nil, mainstacksize);
312         if(kproc == nil)
313                 proccreate(joyproc, nil, mainstacksize*2);
314         bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
315         screeninit();
316 }