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