shithub: sce

Download patch

ref: 694039a3792bd62ac8e086ac710dddd553333bb6
parent: 13e4185989d42efd2d2dad6daddb67a61a55d94d
author: qwx <qwx@sciops.net>
date: Thu Feb 25 18:10:04 EST 2021

sv: decouple simulation from input and drawing

the timeproc shit sucks, but not sure how to do this better.
redrawing should occur immediately when input changes shit
(like panning) even when simulation time is slow, but then
it shouldn't redraw on every single mouse event, so instead
just try to keep to some framerate as usual.  seems sloppy
somehow though.

--- a/dat.h
+++ b/dat.h
@@ -196,8 +196,14 @@
 	Tquit,
 };
 
+enum{
+	Te9 = 1000000000,
+	Te6 = 1000000,
+	Te3 = 1000,
+
+	Tfast = 6,
+};
 extern char *progname, *prefix, *dbname, *mapname;
-extern int clon;
 extern vlong tc;
 extern int pause, debugmap;
 extern int debug;
--- a/drw.c
+++ b/drw.c
@@ -4,6 +4,8 @@
 #include "dat.h"
 #include "fns.h"
 
+extern QLock drawlock;
+
 int scale = 1;
 static Point p0, pan;
 
@@ -16,11 +18,11 @@
 static Mobj **visbuf;
 static int nvisbuf, nvis;
 
-void
-dopan(int dx, int dy)
+int
+dopan(Point p)
 {
-	pan.x -= dx;
-	pan.y -= dy;
+	pan.x -= p.x;
+	pan.y -= p.y;
 	if(pan.x < 0)
 		pan.x = 0;
 	else if(pan.x > panmax.x)
@@ -29,36 +31,43 @@
 		pan.y = 0;
 	else if(pan.y > panmax.y)
 		pan.y = panmax.y;
+	return 1;
 }
 
-void
-select(Point p, int b)
+int
+select(Point p)
 {
 	int i;
+
+	if(!ptinrect(p, selr))
+		return 0;
+	p = divpt(subpt(p, selr.min), scale);
+	i = fbvis[p.y * fbw + p.x];
+	selected[0] = i == -1 ? nil : visbuf[i];
+	return 1;
+}
+
+int
+move(Point p)
+{
+	int i;
 	Point vp;
 	Mobj *mo;
 
-	if(!ptinrect(p, selr))
-		return;
-	if(b & 1){
-		p = divpt(subpt(p, selr.min), scale);
-		i = fbvis[p.y * fbw + p.x];
-		selected[0] = i == -1 ? nil : visbuf[i];
-	}else if(b & 4){
-		if(selected[0] == nil)
-			return;
-		vp = divpt(subpt(p, selr.min), scale);
-		i = fbvis[vp.y * fbw + vp.x];
-		mo = i == -1 ? nil : visbuf[i];
-		if(mo == selected[0]){
-			dprint("select: %#p not moving to itself\n", visbuf[i]);
-			return;
-		}
-		p = divpt(addpt(subpt(p, selr.min), pan), scale);
-		p.x /= Tlsubwidth;
-		p.y /= Tlsubheight;
-		moveone(p, selected[0], mo);
+	if(!ptinrect(p, selr) || selected[0] == nil)
+		return 0;
+	vp = divpt(subpt(p, selr.min), scale);
+	i = fbvis[vp.y * fbw + vp.x];
+	mo = i == -1 ? nil : visbuf[i];
+	if(mo == selected[0]){
+		dprint("select: %#p not moving to itself\n", visbuf[i]);
+		return 0;
 	}
+	p = divpt(addpt(subpt(p, selr.min), pan), scale);
+	p.x /= Tlsubwidth;
+	p.y /= Tlsubheight;
+	moveone(p, selected[0], mo);
+	return 1;
 }
 
 static void
@@ -371,6 +380,15 @@
 	if(debugmap)
 		drawmap(&mr);
 	drawhud();
+}
+
+void
+updatefb(void)
+{
+	qlock(&drawlock);
+	redraw();
+	qunlock(&drawlock);
+	drawfb();
 }
 
 void
--- a/fns.h
+++ b/fns.h
@@ -3,19 +3,23 @@
 void	linktomap(Mobj*);
 int	moveone(Point, Mobj*, Mobj*);
 void	stepsim(void);
-void	initsv(void);
+void	initsim(void);
+void	initsv(int, char*);
 void	flushcl(void);
 void	packcl(char*, ...);
 void	stepnet(void);
 void	joinnet(char*);
 void	listennet(void);
-void	dopan(int, int);
+int	dopan(Point);
+int	select(Point);
+int	move(Point);
 void	compose(int, int, u32int);
 void	redraw(void);
+void	updatefb(void);
 void	resetfb(void);
 void	drawfb(void);
 void	initimg(void);
-void	init(void);
+void	initfs(void);
 void	setgoal(Point*, Mobj*, Mobj*);
 int	isblocked(int, int, Obj*);
 void	markmobj(Mobj*, int);
--- a/fs.c
+++ b/fs.c
@@ -614,12 +614,11 @@
 }
 
 void
-init(void)
+initfs(void)
 {
 	if(bind(".", prefix, MBEFORE|MCREATE) == -1 || chdir(prefix) < 0)
 		fprint(2, "init: %r\n");
 	loaddb(dbname);
 	loaddb(mapname);
-	srand(time(nil));
 	initdb();
 }
--- a/mkfile
+++ b/mkfile
@@ -12,6 +12,7 @@
 	sce.$O\
 	sim.$O\
 	snd.$O\
+	sv.$O\
 	util.$O\
 
 HFILES=dat.h fns.h
--- a/sce.c
+++ b/sce.c
@@ -8,14 +8,15 @@
 #include "dat.h"
 #include "fns.h"
 
-void	select(Point, int);
-
 mainstacksize = 16*1024;
 
+enum{
+	Hz = 60,
+};
+
 char *progname = "sce", *dbname, *prefix, *mapname = "map1.db";
-int clon;
-vlong tc;
 int pause, debugmap;
+QLock drawlock;
 
 typedef struct Kev Kev;
 typedef struct Mev Mev;
@@ -25,19 +26,11 @@
 };
 struct Mev{
 	Point;
-	int dx;
-	int dy;
+	Point Δ;
 	int b;
 };
 
-enum{
-	Te9 = 1000000000,
-	Te6 = 1000000,
-	Tfast = 6,
-};
-static int tv = Tfast, tdiv;
-static vlong Δtc;
-static Channel *reszc, *kc, *mc;
+static Channel *reszc, *kc, *mc, *tmc;
 
 static void
 mproc(void *)
@@ -64,8 +57,8 @@
 			m.x = strtol(buf+1+12*0, nil, 10);
 			m.y = strtol(buf+1+12*1, nil, 10);
 			m.b = strtol(buf+1+12*2, nil, 10);
-			m.dx = m.x - om.x;
-			m.dy = m.y - om.y;
+			m.Δ.x = m.x - om.x;
+			m.Δ.y = m.y - om.y;
 			if((m.b & 1) == 1 && (om.b & 1) == 0
 			|| (m.b & 4) == 4 && (om.b & 4) == 0
 			|| m.b & 2)
@@ -117,84 +110,49 @@
 }
 
 static void
-quit(void)
+timeproc(void *)
 {
-	packcl("u", Tquit);
-	flushcl();
-	threadexitsall(nil);
-}
+	int tdiv;
+	vlong t, t0, dt, Δtc;
 
-static void
-input(void)
-{
-	Kev ke;
-	Mev me;
-
-	if(nbrecv(reszc, nil) != 0){
-		if(getwindow(display, Refnone) < 0)
-			sysfatal("resize failed: %r");
-		resetfb();
+	tdiv = Te9 / Hz;
+	t0 = nsec();
+	for(;;){
+		nbsendul(tmc, 0);
+		t = nsec();
+		Δtc = (t - t0) / tdiv;
+		if(Δtc <= 0)
+			Δtc = 1;
+		t0 += Δtc * tdiv;
+		dt = (t0 - t) / Te6;
+		if(dt > 0)
+			sleep(dt);
 	}
-	while(nbrecv(mc, &me) > 0){
-		if(me.b & 5)
-			select(me, me.b);
-		if(me.b & 2)
-			dopan(me.dx, me.dy);
-	}
-	while(nbrecv(kc, &ke) > 0){
-		if(!ke.down)
-			continue;
-		switch(ke.r){
-		case KF|1: debugmap ^= 1; pause ^= 1; break;
-		case ' ': pause ^= 1; break;
-		case Kdel: quit(); break;
-		}
-	}
 }
 
 static void
-stepcl(void)
-{
-	if(!clon)
-		return;
-	input();
-	flushcl();
-	redraw();
-	drawfb();
-	stepsnd();
-}
-
-static void
 initcl(void)
 {
-	clon = 1;
 	if(initdraw(nil, nil, progname) < 0)
 		sysfatal("initdraw: %r");
+	initsnd();
+	initimg();
+	resetfb();
 	if((reszc = chancreate(sizeof(int), 2)) == nil
 	|| (kc = chancreate(sizeof(Kev), 20)) == nil
-	|| (mc = chancreate(sizeof(Mev), 20)) == nil)
+	|| (mc = chancreate(sizeof(Mev), 20)) == nil
+	|| (tmc = chancreate(sizeof(ulong), 0)) == nil)
 		sysfatal("chancreate: %r");
 	if(proccreate(kproc, nil, 8192) < 0
-	|| proccreate(mproc, nil, 8192) < 0)
+	|| proccreate(mproc, nil, 8192) < 0
+	|| proccreate(timeproc, nil, 8192) < 0)
 		sysfatal("proccreate: %r");
-	initsnd();
-	initimg();
-	resetfb();
 }
 
 static void
-step(void)
-{
-	stepnet();
-	stepcl();
-	while(!pause && Δtc-- > 0)
-		stepsim();
-}
-
-static void
 usage(void)
 {
-	fprint(2, "usage: %s [-D] [-l port] [-m map] [-n name] [-s scale] [-t speed] [-x netmtpt] [sys]\n", argv0);
+	fprint(2, "usage: %s [-D] [-P port] [-m map] [-n name] [-s scale] [-t speed] [-x netmtpt] [sys]\n", argv0);
 	threadexits("usage");
 }
 
@@ -201,11 +159,14 @@
 void
 threadmain(int argc, char **argv)
 {
-	vlong t, t0, dt;
+	int tv;
+	Kev ke;
+	Mev me;
 
+	tv = Tfast;
 	ARGBEGIN{
 	case 'D': debug = 1; break;
-	case 'l': lport = strtol(EARGF(usage()), nil, 0); break;
+	case 'P': lport = strtol(EARGF(usage()), nil, 0); break;
 	case 'm': mapname = EARGF(usage()); break;
 	case 'n': progname = EARGF(usage()); break;
 	case 's':
@@ -230,23 +191,54 @@
 		dbname = smprint("%s.db", progname);
 	if(prefix == nil)
 		prefix = smprint("/sys/games/lib/%s", progname);
-	init();
-	initsv();
+	srand(time(nil));
+	initfs();
+	initsv(tv, *argv);
 	initcl();
-	joinnet(*argv);
-	tdiv = Te9 / (tv * 3);
-	Δtc = 1;
-	t0 = nsec();
+	enum{
+		Aresize,
+		Amouse,
+		Akbd,
+		Atic,
+		Aend,
+	};
+	Alt a[] = {
+		{reszc, nil, CHANRCV},
+		{mc, &me, CHANRCV},
+		{kc, &ke, CHANRCV},
+		{tmc, nil, CHANRCV},
+		{nil, nil, CHANEND}
+	};
 	for(;;){
-		step();
-		tc += 1;
-		t = nsec();
-		Δtc = (t - t0) / tdiv;
-		if(Δtc <= 0)
-			Δtc = 1;
-		t0 += Δtc * tdiv;
-		dt = (t0 - t) / Te6;
-		if(dt > 0)
-			sleep(dt);
+		switch(alt(a)){
+		case Aresize:
+			if(getwindow(display, Refnone) < 0)
+				sysfatal("resize failed: %r");
+			resetfb();
+			break;
+		case Amouse:
+			qlock(&drawlock);	/* just for security */
+			if(me.b & 1)
+				select(me);
+			if(me.b & 2)
+				dopan(me.Δ);
+			if(me.b & 4)
+				move(me);
+			qunlock(&drawlock);
+			break;
+		case Akbd:
+			if(ke.r == Kdel)
+				threadexitsall(nil);
+			if(!ke.down)
+				continue;
+			switch(ke.r){
+			case KF|1: debugmap ^= 1; pause ^= 1; break;
+			case ' ': pause ^= 1; break;
+			}
+			break;
+		case Atic:
+			updatefb();
+			break;
+		}
 	}
 }
--- a/sim.c
+++ b/sim.c
@@ -338,7 +338,7 @@
 		stepmove(oml->mo);
 }
 
-static void
+void
 initsim(void)
 {
 	Team *t;
@@ -347,11 +347,4 @@
 		sysfatal("initgame: the only winning move is not to play");
 	for(t=team; t<=team+nteam; t++)
 		memcpy(t->r, initres, sizeof initres);
-}
-
-void
-initsv(void)
-{
-	initsim();
-	listennet();
 }
--- /dev/null
+++ b/sv.c
@@ -1,0 +1,52 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+extern QLock drawlock;
+
+vlong tc;
+
+static int tdiv;
+
+static void
+step(vlong tics)
+{
+	qlock(&drawlock);
+	while(!pause && tics-- > 0)
+		stepsim();
+	qunlock(&drawlock);
+}
+
+static void
+simproc(void *sys)
+{
+	vlong t, t0, dt, Δtc;
+
+	USED(sys);
+	initsim();
+	Δtc = 1;
+	t0 = nsec();
+	for(;;){
+		step(Δtc);
+		tc += 1;
+		t = nsec();
+		Δtc = (t - t0) / tdiv;
+		if(Δtc <= 0)
+			Δtc = 1;
+		t0 += Δtc * tdiv;
+		dt = (t0 - t) / Te6;
+		if(dt > 0)
+			sleep(dt);
+	}
+}
+
+void
+initsv(int tv, char *sys)
+{
+	tdiv = Te9 / (tv * 3);
+	if(proccreate(simproc, sys, 8192) < 0)
+		sysfatal("proccreate: %r");
+}