shithub: riscv

Download patch

ref: 88537cfe9b483846ccd7367c81fde5dcfe16a4d5
parent: abf8c8bf2cd27541d6a102f7c0385c3fe281f578
author: qwx <devnull@localhost>
date: Sun May 13 03:01:47 EDT 2018

demote libemu to common code

- too small, nothing else that won't be under /games will use it
- "libemu" as a name doesn't make sense here

--- a/sys/man/2/emu
+++ /dev/null
@@ -1,137 +1,0 @@
-.TH EMU 2
-.SH NAME
-initemu, regkeyfn, flushmouse, flushscreen, flushaudio, screenwipe \- graphical emulator-like software scaffolding
-.SH SYNOPSIS
-.nf
-.ft L
-#include <u.h>
-#include <libc.h>
-#include <emu.h>
-.PP
-.ta +\w'\fLvoid fP'u
-.B
-void	flushmouse(int discard);
-.PP
-.B
-void	flushscreen(void);
-.PP
-.B
-void	flushaudio(int (*fn)(void));
-.PP
-.B
-void	regkeyfn(Rune r, void (*fn)(void));
-.PP
-.B
-void	regkey(char *joyk, Rune r, int k);
-.PP
-.B
-void	initemu(int dx, int dy, int bpp, ulong chan,
-.B
-	   int dokey, void(*kproc)(void*));
-.SH DESCRIPTION
-.I Libemu
-implements common user interfaces for programs controlled
-with a joypad or a limited number of keys.
-.PP
-.B initemu
-initializes the display for the given internal screen size
-.B dx
-by
-.B dy
-and
-.B bpp
-bit depth.
-.B Chan
-is an
-.B Image
-pixel format descriptor to be used for an internal framebuffer (see
-.IR draw (2)).
-.PP
-If
-.B dokey
-is true,
-a keyboard process is started which sets a 64-bit wide bit vector for input keys.
-.PP
-Keys are set via
-.B regkey.
-Pressing the key corresponding to the
-.B r
-rune, or writing
-.B joyk
-to standard in will
-.L OR
-.B k
-with the key bit vector.
-.PP
-.B Regkeyfn
-registers an additional rune and a callback for the keyboard process.
-.PP
-Normally, a joypad process is also started, and parses standard input for key presses.
-If
-.B dokey
-is false, only the joypad process will be started.
-If
-.B kproc
-is a valid function pointer,
-it will be used for keyboard processing instead of the library-provided one,
-and no joypad process will be started.
-.PP
-.IP
-.EX
-.ta 6n
-uchar *pic;
-.EE
-.PP
-Once
-.B initemu
-is called, a framebuffer of the specifized size is allocated,
-and may be accessed via
-.BR pic .
-.L Libemu
-scales the framebuffer to fit the greatest multiple of the framebuffer's
-width in the window.
-The scaling is horizontal only and needs to be taken into account for drawing
-within the program.
-.PP
-Typically, mouse event handling is followed by drawing the final image from the
-internal framebuffer render and writing a constant amount of audio samples,
-thereby synchronizing the program's framerate to the audio writes.
-.IP
-.EX
-.ta 6n
-Mouse m;
-extern Mousectl *mc;
-
-flushmouse(0);
-while(nbrecv(mc->c, &m) > 0){
-	...
-}
-flushscreen();
-flushaudio(audioout);
-.EE
-.PP
-Besides window resizing, mouse events are discarded by default.
-If
-.B discard
-is false
-.B flushmouse
-will let the user program handle mouse events prior to flushing the screen (see 
-.BR event (2)).
-.PP
-.B Flushscreen
-handles re-scaling and re-allocating the buffers used, as well as drawing to
-the screen, either directly, or by duplicating pre-scaled scanlines.
-.SH SOURCE
-.B /sys/src/libemu
-.SH "SEE ALSO"
-.IR draw (2),
-.IR event (2)
-.SH BUGS
-The semantics for
-.B initemu
-input selection are confusing.
-.PP
-A greater effort should be made to simplify automatic scaling for user programs.
-.SH HISTORY
-.I Libemu
-first appeared in 9front in May, 2018.
--- a/sys/src/games/2600/2600.c
+++ b/sys/src/games/2600/2600.c
@@ -3,7 +3,7 @@
 #include <thread.h>
 #include <draw.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/2600/cpu.c
+++ b/sys/src/games/2600/cpu.c
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/2600/mem.c
+++ b/sys/src/games/2600/mem.c
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/2600/mkfile
+++ b/sys/src/games/2600/mkfile
@@ -8,7 +8,10 @@
 	cpu.$O\
 	mem.$O\
 	tia.$O\
+	eui.$O\
 
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/2600/tia.c
+++ b/sys/src/games/2600/tia.c
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/c64/c64.c
+++ b/sys/src/games/c64/c64.c
@@ -4,7 +4,7 @@
 #include <draw.h>
 #include <mouse.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/c64/cpu.c
+++ b/sys/src/games/c64/cpu.c
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/c64/mem.c
+++ b/sys/src/games/c64/mem.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/c64/mkfile
+++ b/sys/src/games/c64/mkfile
@@ -7,7 +7,10 @@
 	cpu.$O\
 	mem.$O\
 	vic.$O\
-	
+	eui.$O\
+
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/c64/vic.c
+++ b/sys/src/games/c64/vic.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- /dev/null
+++ b/sys/src/games/eui.c
@@ -1,0 +1,316 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include "eui.h"
+
+typedef struct Kfn Kfn;
+
+u64int keys, keys2;
+int trace, paused;
+int savereq, loadreq;
+QLock pauselock;
+int scale, warp10;
+uchar *pic;
+Rectangle picr;
+Mousectl *mc;
+Image *bg;
+
+static int profile, framestep;
+static int vwdx, vwdy, vwbpp;
+static ulong vwchan;
+static Image *fb;
+
+struct Kfn{
+	Rune r;
+	int k;
+	char joyk[16];
+	void(*fn)(void);
+	Kfn *n;
+};
+Kfn kfn, kkn;
+
+void *
+emalloc(ulong sz)
+{
+	void *v;
+
+	v = mallocz(sz, 1);
+	if(v == nil)
+		sysfatal("malloc: %r");
+	setmalloctag(v, getcallerpc(&sz));
+	return v;
+}
+
+static void
+joyproc(void *)
+{
+	char *s, *down[9];
+	static char buf[64];
+	int n, k, j;
+	Kfn *kp;
+
+	j = 1;
+
+	for(;;){
+		n = read(0, buf, sizeof(buf) - 1);
+		if(n <= 0)
+			sysfatal("read: %r");
+		buf[n] = 0;
+		n = getfields(buf, down, nelem(down), 1, " ");
+		k = 0;
+		for(n--; n >= 0; n--){
+			s = down[n];
+			if(strcmp(s, "joy1") == 0)
+				j = 1;
+			else if(strcmp(s, "joy2") == 0)
+				j = 2;
+			for(kp=kkn.n; kp!=nil; kp=kp->n){
+				if(strcmp(kp->joyk, s) == 0)
+					k |= kp->k;
+			}
+		}
+		if(j == 2)
+			keys2 = k;
+		else
+			keys = k;
+	}
+}
+
+static void
+keyproc(void *)
+{
+	int fd, n, k;
+	static char buf[256];
+	char *s;
+	Rune r;
+	Kfn *kp;
+
+	fd = open("/dev/kbd", OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	for(;;){
+		if(buf[0] != 0){
+			n = strlen(buf)+1;
+			memmove(buf, buf+n, sizeof(buf)-n);
+		}
+		if(buf[0] == 0){
+			n = read(fd, buf, sizeof(buf)-1);
+			if(n <= 0)
+				sysfatal("read /dev/kbd: %r");
+			buf[n-1] = 0;
+			buf[n] = 0;
+		}
+		if(buf[0] == 'c'){
+			if(utfrune(buf, Kdel)){
+				close(fd);
+				threadexitsall(nil);
+			}
+			if(utfrune(buf, KF|5))
+				savereq = 1;
+			if(utfrune(buf, KF|6))
+				loadreq = 1;
+			if(utfrune(buf, KF|12))
+				profile ^= 1;
+			if(utfrune(buf, 't'))
+				trace = !trace;
+			for(kp=kfn.n; kp!=nil; kp=kp->n){
+				if(utfrune(buf, kp->r))
+					kp->fn();
+			}
+		}
+		if(buf[0] != 'k' && buf[0] != 'K')
+			continue;
+		s = buf + 1;
+		k = 0;
+		while(*s != 0){
+			s += chartorune(&r, s);
+			switch(r){
+			case Kdel: close(fd); threadexitsall(nil);
+			case Kesc:
+				if(paused)
+					qunlock(&pauselock);
+				else
+					qlock(&pauselock);
+				paused = !paused;
+				break;
+			case KF|1:	
+				if(paused){
+					qunlock(&pauselock);
+					paused=0;
+				}
+				framestep = !framestep;
+				break;
+			case '`':
+				warp10 = !warp10;
+				break;
+			}
+			for(kp=kkn.n; kp!=nil; kp=kp->n){
+				if(utfrune(buf, kp->r))
+					k |= kp->k;
+			}
+		}
+		k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
+		keys = k;
+	}
+}
+
+static void
+timing(void)
+{
+	static int fcount;
+	static vlong old;
+	static char buf[32];
+	vlong new;
+
+	if(++fcount == 60)
+		fcount = 0;
+	else
+		return;
+	new = nsec();
+	if(new != old)
+		sprint(buf, "%6.2f%%", 1e11 / (new - old));
+	else
+		buf[0] = 0;
+	draw(screen, rectaddpt(Rect(10, 10, vwdx-40, 30), screen->r.min), bg, nil, ZP);
+	string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
+	old = nsec();
+}
+
+static void
+screeninit(void)
+{
+	Point p;
+
+	scale = Dx(screen->r) / vwdx;
+	if(scale <= 0)
+		scale = 1;
+	else if(scale > 16)
+		scale = 16;
+	p = divpt(addpt(screen->r.min, screen->r.max), 2);
+	picr = Rpt(subpt(p, Pt(scale * vwdx/2, scale * vwdy/2)),
+		addpt(p, Pt(scale * vwdx/2, scale * vwdy/2)));
+	freeimage(fb);
+	fb = allocimage(display, Rect(0, 0, scale * vwdx, scale > 1 ? 1 : scale * vwdy),
+		vwchan, scale > 1, 0);
+	free(pic);
+	pic = emalloc(vwdx * vwdy * vwbpp * scale);
+	draw(screen, screen->r, bg, nil, ZP);	
+}
+
+void
+flushmouse(int discard)
+{
+	Mouse m;
+
+	if(nbrecvul(mc->resizec) > 0){
+		if(getwindow(display, Refnone) < 0)
+			sysfatal("resize failed: %r");
+		screeninit();
+	}
+	if(discard)
+		while(nbrecv(mc->c, &m) > 0)
+			;
+}
+
+void
+flushscreen(void)
+{
+	flushmouse(1);
+	if(scale == 1){
+		loadimage(fb, fb->r, pic, vwdx * vwdy * vwbpp);
+		draw(screen, picr, fb, nil, ZP);
+	} else {
+		Rectangle r;
+		uchar *s;
+		int w;
+
+		s = pic;
+		r = picr;
+		w = vwdx * vwbpp * scale;
+		while(r.min.y < picr.max.y){
+			loadimage(fb, fb->r, s, w);
+			s += w;
+			r.max.y = r.min.y+scale;
+			draw(screen, r, fb, nil, ZP);
+			r.min.y = r.max.y;
+		}
+	}
+	flushimage(display, 1);
+	if(profile)
+		timing();
+}
+
+void
+flushaudio(int (*audioout)(void))
+{
+	static vlong old, delta;
+	vlong new, diff;
+
+	if(audioout == nil || audioout() < 0 && !warp10){
+		new = nsec();
+		diff = 0;
+		if(old != 0){
+			diff = BILLION/60 - (new - old) - delta;
+			if(diff >= MILLION)
+				sleep(diff/MILLION);
+		}
+		old = nsec();
+		if(diff > 0){
+			diff = (old - new) - (diff / MILLION) * MILLION;
+			delta += (diff - delta) / 100;
+		}
+	}
+	if(framestep){
+		paused = 1;
+		qlock(&pauselock);
+		framestep = 0;
+	}
+}
+
+void
+regkeyfn(Rune r, void (*fn)(void))
+{
+	Kfn *kp;
+
+	for(kp=&kfn; kp->n!=nil; kp=kp->n)
+		;
+	kp->n = emalloc(sizeof *kp);
+	kp->n->r = r;
+	kp->n->fn = fn;
+}
+
+void
+regkey(char *joyk, Rune r, int k)
+{
+	Kfn *kp;
+
+	for(kp=&kkn; kp->n!=nil; kp=kp->n)
+		;
+	kp->n = emalloc(sizeof *kp);
+	strncpy(kp->n->joyk, joyk, sizeof(kp->n->joyk)-1);
+	kp->n->r = r;
+	kp->n->k = k;
+}
+
+void
+initemu(int dx, int dy, int bpp, ulong chan, int dokey, void(*kproc)(void*))
+{
+	vwdx = dx;
+	vwdy = dy;
+	vwchan = chan;
+	vwbpp = bpp;
+	if(initdraw(nil, nil, nil) < 0)
+		sysfatal("initdraw: %r");
+	mc = initmouse(nil, screen);
+	if(mc == nil)
+		sysfatal("initmouse: %r");
+	if(dokey)
+		proccreate(kproc != nil ? kproc : keyproc, nil, mainstacksize);
+	if(kproc == nil)
+		proccreate(joyproc, nil, mainstacksize*2);
+	bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+	screeninit();
+}
--- /dev/null
+++ b/sys/src/games/eui.h
@@ -1,0 +1,19 @@
+enum{
+	MILLION = 1000000,
+	BILLION = 1000000000,
+};
+
+extern u64int keys, keys2;
+extern int trace, paused;
+extern int savereq, loadreq;
+extern QLock pauselock;
+extern int scale, warp10;
+extern uchar *pic;
+
+void*	emalloc(ulong);
+void	flushmouse(int);
+void	flushscreen(void);
+void	flushaudio(int(*)(void));
+void	regkeyfn(Rune, void(*)(void));
+void	regkey(char*, Rune, int);
+void	initemu(int, int, int, ulong, int, void(*)(void*));
--- a/sys/src/games/gb/apu.c
+++ b/sys/src/games/gb/apu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gb/cpu.c
+++ b/sys/src/games/gb/cpu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gb/gb.c
+++ b/sys/src/games/gb/gb.c
@@ -3,7 +3,7 @@
 #include <thread.h>
 #include <draw.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gb/mem.c
+++ b/sys/src/games/gb/mem.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gb/mkfile
+++ b/sys/src/games/gb/mkfile
@@ -10,7 +10,10 @@
 	ev.$O\
 	state.$O\
 	apu.$O\
+	eui.$O\
 
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gba/apu.c
+++ b/sys/src/games/gba/apu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gba/cpu.c
+++ b/sys/src/games/gba/cpu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gba/gba.c
+++ b/sys/src/games/gba/gba.c
@@ -3,7 +3,7 @@
 #include <thread.h>
 #include <draw.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gba/mem.c
+++ b/sys/src/games/gba/mem.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/gba/mkfile
+++ b/sys/src/games/gba/mkfile
@@ -10,7 +10,10 @@
 	ev.$O\
 	apu.$O\
 	state.$O\
+	eui.$O\
 
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/gba/ppu.c
+++ b/sys/src/games/gba/ppu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/md/cpu.c
+++ b/sys/src/games/md/cpu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/md/md.c
+++ b/sys/src/games/md/md.c
@@ -3,7 +3,7 @@
 #include <thread.h>
 #include <draw.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/md/mem.c
+++ b/sys/src/games/md/mem.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/md/mkfile
+++ b/sys/src/games/md/mkfile
@@ -9,7 +9,10 @@
 	vdp.$O\
 	z80.$O\
 	ym.$O\
+	eui.$O\
 
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/md/vdp.c
+++ b/sys/src/games/md/vdp.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/md/ym.c
+++ b/sys/src/games/md/ym.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/nes/apu.c
+++ b/sys/src/games/nes/apu.c
@@ -2,7 +2,7 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/nes/mem.c
+++ b/sys/src/games/nes/mem.c
@@ -2,7 +2,7 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/nes/mkfile
+++ b/sys/src/games/nes/mkfile
@@ -9,7 +9,10 @@
 	ppu.$O\
 	state.$O\
 	apu.$O\
+	eui.$O\
 	
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/nes/nes.c
+++ b/sys/src/games/nes/nes.c
@@ -3,7 +3,7 @@
 #include <draw.h>
 #include <thread.h>
 #include <keyboard.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/nes/ppu.c
+++ b/sys/src/games/nes/ppu.c
@@ -3,7 +3,7 @@
 #include <thread.h>
 #include <draw.h>
 #include <mouse.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/cpu.c
+++ b/sys/src/games/snes/cpu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/dsp.c
+++ b/sys/src/games/snes/dsp.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/mem.c
+++ b/sys/src/games/snes/mem.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/mkfile
+++ b/sys/src/games/snes/mkfile
@@ -10,7 +10,10 @@
 	spc.$O\
 	dsp.$O\
 	state.$O\
+	eui.$O\
 
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
+eui.$O: ../eui.c
+	$CC $CFLAGS ../eui.c
--- a/sys/src/games/snes/ppu.c
+++ b/sys/src/games/snes/ppu.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/snes.c
+++ b/sys/src/games/snes/snes.c
@@ -4,7 +4,7 @@
 #include <draw.h>
 #include <keyboard.h>
 #include <mouse.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/games/snes/spc.c
+++ b/sys/src/games/snes/spc.c
@@ -1,7 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include <emu.h>
+#include "../eui.h"
 #include "dat.h"
 #include "fns.h"
 
--- a/sys/src/libemu/emu.c
+++ /dev/null
@@ -1,316 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <draw.h>
-#include <keyboard.h>
-#include <mouse.h>
-#include <emu.h>
-
-typedef struct Kfn Kfn;
-
-u64int keys, keys2;
-int trace, paused;
-int savereq, loadreq;
-QLock pauselock;
-int scale, warp10;
-uchar *pic;
-Rectangle picr;
-Mousectl *mc;
-Image *bg;
-
-static int profile, framestep;
-static int vwdx, vwdy, vwbpp;
-static ulong vwchan;
-static Image *fb;
-
-struct Kfn{
-	Rune r;
-	int k;
-	char joyk[16];
-	void(*fn)(void);
-	Kfn *n;
-};
-Kfn kfn, kkn;
-
-void *
-emalloc(ulong sz)
-{
-	void *v;
-
-	v = mallocz(sz, 1);
-	if(v == nil)
-		sysfatal("malloc: %r");
-	setmalloctag(v, getcallerpc(&sz));
-	return v;
-}
-
-static void
-joyproc(void *)
-{
-	char *s, *down[9];
-	static char buf[64];
-	int n, k, j;
-	Kfn *kp;
-
-	j = 1;
-
-	for(;;){
-		n = read(0, buf, sizeof(buf) - 1);
-		if(n <= 0)
-			sysfatal("read: %r");
-		buf[n] = 0;
-		n = getfields(buf, down, nelem(down), 1, " ");
-		k = 0;
-		for(n--; n >= 0; n--){
-			s = down[n];
-			if(strcmp(s, "joy1") == 0)
-				j = 1;
-			else if(strcmp(s, "joy2") == 0)
-				j = 2;
-			for(kp=kkn.n; kp!=nil; kp=kp->n){
-				if(strcmp(kp->joyk, s) == 0)
-					k |= kp->k;
-			}
-		}
-		if(j == 2)
-			keys2 = k;
-		else
-			keys = k;
-	}
-}
-
-static void
-keyproc(void *)
-{
-	int fd, n, k;
-	static char buf[256];
-	char *s;
-	Rune r;
-	Kfn *kp;
-
-	fd = open("/dev/kbd", OREAD);
-	if(fd < 0)
-		sysfatal("open: %r");
-	for(;;){
-		if(buf[0] != 0){
-			n = strlen(buf)+1;
-			memmove(buf, buf+n, sizeof(buf)-n);
-		}
-		if(buf[0] == 0){
-			n = read(fd, buf, sizeof(buf)-1);
-			if(n <= 0)
-				sysfatal("read /dev/kbd: %r");
-			buf[n-1] = 0;
-			buf[n] = 0;
-		}
-		if(buf[0] == 'c'){
-			if(utfrune(buf, Kdel)){
-				close(fd);
-				threadexitsall(nil);
-			}
-			if(utfrune(buf, KF|5))
-				savereq = 1;
-			if(utfrune(buf, KF|6))
-				loadreq = 1;
-			if(utfrune(buf, KF|12))
-				profile ^= 1;
-			if(utfrune(buf, 't'))
-				trace = !trace;
-			for(kp=kfn.n; kp!=nil; kp=kp->n){
-				if(utfrune(buf, kp->r))
-					kp->fn();
-			}
-		}
-		if(buf[0] != 'k' && buf[0] != 'K')
-			continue;
-		s = buf + 1;
-		k = 0;
-		while(*s != 0){
-			s += chartorune(&r, s);
-			switch(r){
-			case Kdel: close(fd); threadexitsall(nil);
-			case Kesc:
-				if(paused)
-					qunlock(&pauselock);
-				else
-					qlock(&pauselock);
-				paused = !paused;
-				break;
-			case KF|1:	
-				if(paused){
-					qunlock(&pauselock);
-					paused=0;
-				}
-				framestep = !framestep;
-				break;
-			case '`':
-				warp10 = !warp10;
-				break;
-			}
-			for(kp=kkn.n; kp!=nil; kp=kp->n){
-				if(utfrune(buf, kp->r))
-					k |= kp->k;
-			}
-		}
-		k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
-		keys = k;
-	}
-}
-
-static void
-timing(void)
-{
-	static int fcount;
-	static vlong old;
-	static char buf[32];
-	vlong new;
-
-	if(++fcount == 60)
-		fcount = 0;
-	else
-		return;
-	new = nsec();
-	if(new != old)
-		sprint(buf, "%6.2f%%", 1e11 / (new - old));
-	else
-		buf[0] = 0;
-	draw(screen, rectaddpt(Rect(10, 10, vwdx-40, 30), screen->r.min), bg, nil, ZP);
-	string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
-	old = nsec();
-}
-
-static void
-screeninit(void)
-{
-	Point p;
-
-	scale = Dx(screen->r) / vwdx;
-	if(scale <= 0)
-		scale = 1;
-	else if(scale > 16)
-		scale = 16;
-	p = divpt(addpt(screen->r.min, screen->r.max), 2);
-	picr = Rpt(subpt(p, Pt(scale * vwdx/2, scale * vwdy/2)),
-		addpt(p, Pt(scale * vwdx/2, scale * vwdy/2)));
-	freeimage(fb);
-	fb = allocimage(display, Rect(0, 0, scale * vwdx, scale > 1 ? 1 : scale * vwdy),
-		vwchan, scale > 1, 0);
-	free(pic);
-	pic = emalloc(vwdx * vwdy * vwbpp * scale);
-	draw(screen, screen->r, bg, nil, ZP);	
-}
-
-void
-flushmouse(int discard)
-{
-	Mouse m;
-
-	if(nbrecvul(mc->resizec) > 0){
-		if(getwindow(display, Refnone) < 0)
-			sysfatal("resize failed: %r");
-		screeninit();
-	}
-	if(discard)
-		while(nbrecv(mc->c, &m) > 0)
-			;
-}
-
-void
-flushscreen(void)
-{
-	flushmouse(1);
-	if(scale == 1){
-		loadimage(fb, fb->r, pic, vwdx * vwdy * vwbpp);
-		draw(screen, picr, fb, nil, ZP);
-	} else {
-		Rectangle r;
-		uchar *s;
-		int w;
-
-		s = pic;
-		r = picr;
-		w = vwdx * vwbpp * scale;
-		while(r.min.y < picr.max.y){
-			loadimage(fb, fb->r, s, w);
-			s += w;
-			r.max.y = r.min.y+scale;
-			draw(screen, r, fb, nil, ZP);
-			r.min.y = r.max.y;
-		}
-	}
-	flushimage(display, 1);
-	if(profile)
-		timing();
-}
-
-void
-flushaudio(int (*audioout)(void))
-{
-	static vlong old, delta;
-	vlong new, diff;
-
-	if(audioout == nil || audioout() < 0 && !warp10){
-		new = nsec();
-		diff = 0;
-		if(old != 0){
-			diff = BILLION/60 - (new - old) - delta;
-			if(diff >= MILLION)
-				sleep(diff/MILLION);
-		}
-		old = nsec();
-		if(diff > 0){
-			diff = (old - new) - (diff / MILLION) * MILLION;
-			delta += (diff - delta) / 100;
-		}
-	}
-	if(framestep){
-		paused = 1;
-		qlock(&pauselock);
-		framestep = 0;
-	}
-}
-
-void
-regkeyfn(Rune r, void (*fn)(void))
-{
-	Kfn *kp;
-
-	for(kp=&kfn; kp->n!=nil; kp=kp->n)
-		;
-	kp->n = emalloc(sizeof *kp);
-	kp->n->r = r;
-	kp->n->fn = fn;
-}
-
-void
-regkey(char *joyk, Rune r, int k)
-{
-	Kfn *kp;
-
-	for(kp=&kkn; kp->n!=nil; kp=kp->n)
-		;
-	kp->n = emalloc(sizeof *kp);
-	strncpy(kp->n->joyk, joyk, sizeof(kp->n->joyk)-1);
-	kp->n->r = r;
-	kp->n->k = k;
-}
-
-void
-initemu(int dx, int dy, int bpp, ulong chan, int dokey, void(*kproc)(void*))
-{
-	vwdx = dx;
-	vwdy = dy;
-	vwchan = chan;
-	vwbpp = bpp;
-	if(initdraw(nil, nil, nil) < 0)
-		sysfatal("initdraw: %r");
-	mc = initmouse(nil, screen);
-	if(mc == nil)
-		sysfatal("initmouse: %r");
-	if(dokey)
-		proccreate(kproc != nil ? kproc : keyproc, nil, mainstacksize);
-	if(kproc == nil)
-		proccreate(joyproc, nil, mainstacksize*2);
-	bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-	screeninit();
-}
--- a/sys/src/libemu/mkfile
+++ /dev/null
@@ -1,20 +1,0 @@
-</$objtype/mkfile
-
-LIB=/$objtype/lib/libemu.a
-
-OFILES=\
-	emu.$O\
-
-HFILES=\
-	/sys/include/draw.h\
-	/sys/include/emu.h\
-	/sys/include/mouse.h\
-	/sys/include/keyboard.h
-
-UPDATE=\
-	mkfile\
-	$HFILES\
-	${OFILES:%.$O=%.c}\
-	${LIB:/$objtype/%=/386/%}\
-
-</sys/src/cmd/mksyslib