ref: 3891487cd9fb5088d99344d33cf4e37e0abf7f9b
parent: 4c670f454f76120455674cd064d3f9bbb2e0d2aa
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Fri Mar 25 22:18:30 EDT 2016
basic multithread keyboard and mouse, timing, ordering - fix wrong reference palette in fadeout, making it appear too fast - new bug: timecode ripped from aiju won't work if fps < Tb Hz
--- a/dat.h
+++ b/dat.h
@@ -9,7 +9,22 @@
};
extern int ver;
extern char *ext;
-extern int debug, nointro;
+extern int grabon;
+enum{
+ K↑,
+ K↓,
+ K←,
+ K→,
+ Krun,
+ Kfire,
+ Kopen,
+ Kstrafe,
+ Kmenu,
+ Ke
+};
+extern int cson, kbon, mson;
+extern Rune keys[];
+extern int (*step)(void);
enum{
Vw = 320,
@@ -26,7 +41,7 @@
C0,
Cred,
Cwht = Cred+6,
- Caux = Cwht+3,
+ Cfad = Cwht+3,
Csod,
Cend
};
@@ -166,6 +181,11 @@
Spear = Sottodeath,
Sangeltired = Sotto,
Ssend = Sfett,
+
+ Mintro = 7,
+ Mmenu = 14,
+ Mnazjazz = 18,
+ Mtower = 23,
Pbackdrop = 0,
Pmouselback,
--- a/fns.h
+++ b/fns.h
@@ -1,11 +1,13 @@
void* emalloc(ulong);
void* erealloc(void *, ulong);
+void grab(int);
+void toss(void);
void flush(void);
void dat(char *);
-void palpic(uchar *);
-void fadeout(int);
-void fadein(int);
void out(void);
+void fade(void);
+void fadeop(int, u32int, int);
+void palpic(uchar *);
void put(int, int, int, int, uchar *, int);
int txt(int, int, char *, int);
int txtnl(int, int, char *, int);
@@ -12,11 +14,12 @@
int txtw(char *s);
void fill(int);
void pic(int, int, int);
-void demos(void);
-void init(void);
+int estep(void);
+int mstep(void);
+void init(int);
int rnd(void);
-void vbl(int);
-void delay(int);
+int gstep(void);
+int dstep(void);
void initg(int);
void stopmus(void);
void playmus(int);
--- a/gm.c
+++ b/gm.c
@@ -1,8 +1,26 @@
#include <u.h>
#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
#include "dat.h"
#include "fns.h"
+extern Channel *kbc, *msc;
+
+Rune keys[Ke] = {
+ [K↑] Kup,
+ [K↓] Kdown,
+ [K←] Kleft,
+ [K→] Kright,
+ [Krun] Kshift,
+ [Kfire] Kctl,
+ [Kopen] ' ',
+ [Kstrafe] Kalt,
+ [Kmenu] Kesc
+};
+
static int rndi, rndt[] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21,
211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48,
@@ -29,16 +47,17 @@
return rndt[rndi];
}
-void
-vbl(int n)
+int
+gstep(void)
{
- sleep(1000/70 * n);
+ return 0;
}
-void
-delay(int n)
+int
+dstep(void)
{
- vbl(Tb * n);
+ step = mstep;
+ return 0;
}
void
@@ -45,4 +64,8 @@
initg(int r)
{
rndi = r ? time(nil) & 0xff : 0;
+ cson = 0;
+ toss();
+ kbon++;
+ grab(1);
}
--- a/mn.c
+++ b/mn.c
@@ -1,9 +1,16 @@
#include <u.h>
#include <libc.h>
+#include <thread.h>
+#include <keyboard.h>
#include "dat.h"
#include "fns.h"
+extern Channel *csc;
+
typedef struct Score Score;
+typedef struct Menu Menu;
+typedef struct Seq Seq;
+
struct Score{
char name[58];
int n;
@@ -22,9 +29,59 @@
static void (*clear)(void);
static void (*stripe)(int);
-static void (*scores)(void);
-static void (*title)(void);
+struct Seq{
+ int dt;
+ void (*f)(void);
+};
+struct Menu{
+ void (*draw)(void);
+ int nq;
+ Seq *sq;
+ Menu *m;
+};
+static Menu *mp;
+static Seq *msq;
+static int tc;
+
+static void waitkb(void);
+static void menuk(void);
+static void menu(void);
+static void pants(void);
+static void demo(void);
+static void scores(void);
+static void creds(void);
+static void title(void);
+static void intro(void);
+
+static Seq menuq[] = {{1, menuk}};
+static Seq mfadeq[] = {{30, fade}};
+static Seq pantsq[] = {{30, fade}, {600*Tb, waitkb}, {30, fade}};
+static Seq demoq[] = {{1, demo}};
+static Seq loopq[] = {{30, fade}, {10*Tb, waitkb}, {30, fade}};
+static Seq titleq[] = {{30, fade}, {15*Tb, waitkb}, {30, fade}};
+static Seq introq[] = {{30, fade}, {7*Tb, waitkb}, {30, fade}};
+enum{
+ Lmenu,
+ Lmfade,
+ Lpants,
+ Ldemo,
+ Lscores,
+ Lcreds,
+ Ltitle,
+ Lintro
+};
+static Menu ml[] = {
+ [Lmenu] {menu, nelem(menuq), menuq, ml+Lmenu},
+ [Lmfade] {nil, nelem(mfadeq), mfadeq, ml+Lmenu},
+ [Lpants] {pants, nelem(pantsq), pantsq, ml+Lmenu},
+ [Ldemo] {demo, nelem(demoq), demoq, ml+Ltitle},
+ [Lscores] {scores, nelem(loopq), loopq, ml+Ldemo},
+ [Lcreds] {creds, nelem(loopq), loopq, ml+Lscores},
+ [Ltitle] {title, nelem(titleq), titleq, ml+Lcreds},
+ [Lintro] {intro, nelem(introq), introq, ml+Ltitle},
+};
+
static void
wlclear(void)
{
@@ -50,32 +107,69 @@
}
static void
+fixedw(char *s)
+{
+ char c;
+
+ while(c = *s, c != 0)
+ *s++ = c - '0' + 129;
+}
+
+static void
+reset(Menu *m, int pal0)
+{
+ mp = m;
+ tc = 0;
+ if(pal0)
+ pal = pals[C0];
+ msq = m->sq;
+ if(mp->draw != nil){
+ mp->draw();
+ fadeop(msq->dt, 0, 0);
+ }else
+ fadeop(msq->dt, 0, 1);
+}
+
+static void
+waitkb(void)
+{
+ if(nbrecv(csc, nil) > 0)
+ reset(ml+Lmfade, 0);
+}
+
+static void
+menuk(void)
+{
+ Rune r;
+
+ while(nbrecv(csc, &r) != 0);
+}
+
+static void
pants(void)
{
- fadeout(45);
- playmus(18);
pic(0, 0, pict[Pid1]);
pic(0, 80, pict[Pid2]);
palpic(exts[Eid].p);
- fadein(30);
- /* wait for input */
- delay(15);
- fadeout(45);
- pal = pals[C0];
- /* draw main menu */
+ playmus(Mnazjazz);
}
static void
-fixedw(char *s)
+menu(void)
{
- char c;
+ playmus(Mmenu);
+ grab(0);
+ step = estep;
+}
- while(c = *s, c != 0)
- *s++ = c - '0' + 129;
+static void
+demo(void)
+{
+ step = dstep;
}
static void
-wlscores(void)
+scores(void)
{
int x, y;
char a[16], b[16];
@@ -133,9 +227,16 @@
}
static void
-wltitle(void)
+creds(void)
{
+ pic(0, 0, pict[Pcreds]);
+}
+
+static void
+title(void)
+{
pic(0, 0, pict[Ptitle1]);
+ playmus(Mintro);
}
static void
sdtitle(void)
@@ -143,6 +244,7 @@
pic(0, 0, pict[Ptitle1]);
pic(0, 80, pict[Ptitle2]);
palpic(exts[Etitpal].p);
+ playmus(Mtower);
}
static void
@@ -150,53 +252,47 @@
{
fill(0x82);
pic(216, 110, pict[Ppg13]);
- fadein(40);
- delay(7);
- fadeout(40);
+ playmus(Mintro);
}
+static void
+sdintro(void)
+{
+ fill(0x82);
+ pic(216, 110, pict[Ppg13]);
+ playmus(Mtower);
+}
-void
-init(void)
+int
+estep(void)
{
- if(ver < SDM){
- clear = wlclear;
- stripe = wlstripe;
- scores = wlscores;
- title = wltitle;
- }else{
- clear = sdclear;
- stripe = sdstripe;
- scores = sdscores;
- title = sdtitle;
+ return -1;
+}
+
+int
+mstep(void)
+{
+ tc++;
+ msq->f();
+ if(tc == msq->dt){
+ if(++msq == mp->sq + mp->nq)
+ reset(mp->m, 1);
+ tc = 0;
}
- if(!nointro)
- intro();
+ return 0;
}
void
-demos(void)
+init(int nointro)
{
- for(;;){
- if(nointro)
- goto stop;
- title();
- fadein(30);
- delay(15);
- fadeout(40);
- pal = pals[C0];
-
- pic(0, 0, pict[Pcreds]);
- fadein(30);
- delay(10);
- fadeout(40);
-
- scores();
- fadein(30);
- delay(10);
- fadeout(40);
-
- continue;
- stop:
- break;
+ clear = wlclear;
+ stripe = wlstripe;
+ if(ver >= SDM){
+ clear = sdclear;
+ stripe = sdstripe;
+ ml[Lintro].draw = sdintro;
+ ml[Ltitle].draw = sdtitle;
+ ml[Lscores].draw = sdscores;
}
+ reset(nointro ? ml+Lmenu : ml+Lintro, 0);
+ cson++;
}
--- a/rend.c
+++ b/rend.c
@@ -12,16 +12,18 @@
int scale, npx;
uchar *px;
static uchar pxb[Va];
+static void (*ffp)(void);
+static int fi, fdt, fr, fg, fb;
+static u32int *fref;
static void
-modpal(u32int *d, u32int *s, u32int c, int n, int steps)
+fadeout(void)
{
- int r, g, b, u, v, w;
- u32int p, *e;
+ int u, v, w;
+ u32int p, *s, *d, *e;
- b = (c&0xff) * 255 / 63;
- g = (c>>8&0xff) * 255 / 63;
- r = (c>>16&0xff) * 255 / 63;
+ s = fref;
+ d = pal;
e = d+nelem(pals[0]);
while(d < e){
p = *s++;
@@ -28,68 +30,67 @@
u = p & 0xff;
v = p>>8 & 0xff;
w = p>>16 & 0xff;
- u = u + (b-u) * n/steps;
- v = v + (g-v) * n/steps;
- w = w + (r-w) * n/steps;
+ u = u + (fb-u) * fi/fdt;
+ v = v + (fg-v) * fi/fdt;
+ w = w + (fr-w) * fi/fdt;
*d++ = w<<16 | v<<8 | u;
}
}
-void
-palpic(uchar *s)
+static void
+fadein(void)
{
- u32int *p, *e;
+ int u, v, w;
+ u32int p, *s, *d, *e;
- p = pals[Csod];
- e = p + nelem(pals[Csod]);
- while(p < e){
- *p++ = s[0]*255/63<<16 | s[1]*255/63<<8 | s[2]*255/63;
- s += 3;
+ s = fref;
+ d = pal;
+ e = d+nelem(pals[0]);
+ while(d < e){
+ p = *s++;
+ u = (p & 0xff) * fi/fdt;
+ v = (p>>8 & 0xff) * fi/fdt;
+ w = (p>>16 & 0xff) * fi/fdt;
+ *d++ = w<<16 | v<<8 | u;
}
- pal = pals[Csod];
}
void
-fadeout(int steps)
+fade(void)
{
- int i;
- u32int *o;
-
- o = pal;
- pal = pals[Caux];
- vbl(1);
- for(i=0; i<steps; i++){
- modpal(pals[Caux], pal, 0, i, steps);
- vbl(1);
- out();
+ ffp();
+ out();
+ if(fi == fdt && ffp == fadein){
+ ffp = fadeout;
+ fi = 0;
}
- pal = o;
+ fi++;
}
void
-fadein(int steps)
+fadeop(int dt, u32int c, int noin)
{
- int i, u, v, w;
- u32int *o, p, *s, *d, *e;
+ fdt = dt;
+ fb = (c & 0xff) * 255 / 63;
+ fg = (c>>8 & 0xff) * 255 / 63;
+ fr = (c>>16 & 0xff) * 255 / 63;
+ fref = pal;
+ pal = pals[Cfad];
+ fi = 1;
+ ffp = noin ? fadeout : fadein;
+}
- o = pal;
- pal = pals[Caux];
- vbl(1);
- for(i=0; i<steps; i++){
- s = o;
- d = pal;
- e = d+nelem(pals[Caux]);
- while(d < e){
- p = *s++;
- u = (p & 0xff) * i/steps;
- v = (p>>8 & 0xff) * i/steps;
- w = (p>>16 & 0xff) * i/steps;
- *d++ = w<<16 | v<<8 | u;
- }
- vbl(1);
- out();
+void
+palpic(uchar *s)
+{
+ u32int *p, *e;
+
+ p = pal = pals[Csod];
+ e = p + nelem(pals[0]);
+ while(p < e){
+ *p++ = s[0]*255/63<<16 | s[1]*255/63<<8 | s[2]*255/63;
+ s += 3;
}
- pal = o;
}
void
--- a/wl3d.c
+++ b/wl3d.c
@@ -9,11 +9,139 @@
mainstacksize = 16*1024;
char *ext = "wl6";
-int debug, nointro;
+int grabon;
+int cson, kbon, mson;
+int (*step)(void);
+Channel *csc, *kbc, *msc;
-static Rectangle fbr;
+enum{
+ BILLION = 1000000000,
+ MILLION = 1000000
+};
+static Point p0;
+static Rectangle fbr, grabr;
static Image *fb;
+static Channel *reszc;
+static void
+mproc(void *)
+{
+ int n, fd, nerr;
+ char buf[1+5*12], *px, *py, *pb;
+ Point o, p;
+ Mouse m;
+
+ fd = open("/dev/mouse", ORDWR);
+ if(fd < 0)
+ sysfatal("mproc: %r");
+ nerr = 0;
+ px = buf+1;
+ py = px + 12;
+ pb = py + 12;
+ o = p0;
+ for(;;){
+ n = read(fd, buf, sizeof buf);
+ if(n != 1+4*12){
+ if(n < 0 || ++nerr > 10)
+ break;
+ fprint(2, "mproc: bad count %d not 49: %r\n", n);
+ continue;
+ }
+ nerr = 0;
+ switch(*buf){
+ case 'r':
+ send(reszc, nil);
+ /* wet floor */
+ case 'm':
+ if(!mson)
+ break;
+ p.x = strtol(px, nil, 10);
+ p.y = strtol(py, nil, 10);
+ m.xy.x = p.x - o.x;
+ m.xy.y = o.y - p.y;
+ m.buttons = *pb;
+ nbsend(msc, &m);
+ if(!ptinrect(p, grabr)){
+ fprint(fd, "m%d %d", p0.x, p0.y);
+ p = p0;
+ }
+ o = p;
+ }
+ }
+}
+
+static void
+kproc(void *)
+{
+ int n, k, fd;
+ char c, buf[256], *s;
+ Rune r, *a;
+
+ fd = open("/dev/kbd", OREAD);
+ if(fd < 0)
+ sysfatal("kproc: %r");
+ memset(buf, 0, sizeof buf);
+ for(;;){
+ n = read(fd, buf, sizeof(buf)-1);
+ if(n <= 0)
+ break;
+ c = *buf;
+ if(c == 'c' && cson){
+ chartorune(&r, buf+1);
+ send(csc, &r);
+ }
+ if(c != 'k' || c != 'K' || !kbon)
+ continue;
+ s = buf+1;
+ k = 0;
+ while(*s != 0){
+ s += chartorune(&r, s);
+ for(a=keys; a<keys+Ke; a++)
+ if(r == *a){
+ k |= 1<<a-keys;
+ break;
+ }
+ }
+ send(kbc, &k);
+ }
+}
+
+static void
+resetfb(void)
+{
+ Point p, d;
+
+ scale = Dx(screen->r) / Vw;
+ if(scale <= 0)
+ scale = 1;
+ else if(scale > 10)
+ scale = 10;
+ p = divpt(addpt(screen->r.min, screen->r.max), 2);
+ d = Pt(Vw/2 * scale, Vh/2 * scale);
+ fbr = Rpt(subpt(p, d), addpt(p, d));
+ d = Pt(Vh/4, Vh/4);
+ grabr = Rpt(subpt(p, d), addpt(p, d));
+ p0 = p;
+
+ freeimage(fb);
+ free(px);
+ npx = Vt * scale;
+ px = emalloc(npx);
+ fb = allocimage(display, Rect(0,0,Vw*scale,scale==1 ? Vh : 1), RGB24, 1, 0);
+ if(fb == nil)
+ sysfatal("resetfb: %r");
+
+ draw(screen, screen->r, display->black, nil, ZP);
+ out();
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s [-23dios] [-m dir] [-w map] [-x difficulty]\n", argv0);
+ threadexits("usage");
+}
+
void *
emalloc(ulong n)
{
@@ -36,6 +164,35 @@
}
void
+grab(int on)
+{
+ static char nocurs[2*4+2*2*16];
+ static int fd = -1;
+
+ if(mson == on)
+ return;
+ if(mson = on && grabon){
+ fd = open("/dev/cursor", ORDWR|OCEXEC);
+ if(fd < 0){
+ fprint(2, "grab: %r\n");
+ return;
+ }
+ write(fd, nocurs, sizeof nocurs);
+ }else if(fd >= 0){
+ close(fd);
+ fd = -1;
+ }
+}
+
+void
+toss(void)
+{
+ while(nbrecv(csc, nil) != 0);
+ while(nbrecv(msc, nil) != 0);
+ while(nbrecv(kbc, nil) != 0);
+}
+
+void
flush(void)
{
Rectangle r;
@@ -57,49 +214,20 @@
flushimage(display, 1);
}
-static void
-resetfb(void)
-{
- Point p, d;
-
- scale = Dx(screen->r) / Vw;
- if(scale <= 0)
- scale = 1;
- else if(scale > 10)
- scale = 10;
- p = divpt(addpt(screen->r.min, screen->r.max), 2);
- d = Pt(Vw/2 * scale, Vh/2 * scale);
- fbr = Rpt(subpt(p, d), addpt(p, d));
-
- freeimage(fb);
- free(px);
- npx = Vt * scale;
- px = emalloc(npx);
- fb = allocimage(display, Rect(0,0,Vw*scale,scale==1 ? Vh : 1), RGB24, 1, 0);
- if(fb == nil)
- sysfatal("resetfb: %r");
-
- draw(screen, screen->r, display->black, nil, ZP);
-}
-
-static void
-usage(void)
-{
- fprint(2, "usage: %s [-23Ddios] [-m dir] [-w map] [-x difficulty]\n", argv0);
- threadexits("usage");
-}
-
void
threadmain(int argc, char **argv)
{
+ int n;
+ vlong t0, t, dt, Δ;
char *datdir = "/sys/games/lib/wl3d/";
+ n = 0;
+ step = mstep;
ARGBEGIN{
case '2': ext = "sd2"; break;
case '3': ext = "sd3"; break;
- case 'D': debug++; break;
case 'd': ext = "wl1"; break;
- case 'i': nointro++; break;
+ case 'i': n++; break;
case 'm': datdir = EARGF(usage()); break;
case 'o': ext = "sdm"; break;
case 's': ext = "sod"; break;
@@ -113,9 +241,37 @@
if(initdraw(nil, nil, "wl3d") < 0)
sysfatal("initdraw: %r");
resetfb();
+ kbc = chancreate(sizeof(int), 20);
+ csc = chancreate(sizeof(Rune), 20);
+ reszc = chancreate(sizeof(int), 2);
+ msc = chancreate(sizeof(Mouse), 0);
+ if(kbc == nil || csc == nil | reszc == nil || msc == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(kproc, nil, 8192) < 0 || proccreate(mproc, nil, 8192) < 0)
+ sysfatal("proccreate: %r");
- init();
- demos();
-
+ init(n);
+ t0 = Δ = 0;
+ for(;;){
+ if(nbrecv(reszc, nil) != 0){
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");
+ resetfb();
+ }
+ if(step() < 0)
+ break;
+ t = nsec();
+ dt = 0;
+ if(t0 != 0){
+ dt = BILLION/Tb - (t - t0) - Δ;
+ if(dt >= MILLION)
+ sleep(dt/MILLION);
+ }
+ t0 = nsec();
+ if(dt != 0){
+ dt = (t0 - t) - (dt / MILLION) * MILLION;
+ Δ += (dt - Δ) / 100;
+ }
+ }
threadexitsall(nil);
}