ref: 0c330bc0d2d56af57af2b40fc2e3765dd9d114ef
author: qwx <qwx@sciops.net>
date: Mon Feb 22 10:48:55 EST 2021
3d01: absolute basic 3d view of map and actor
--- /dev/null
+++ b/3d01.c
@@ -1,0 +1,125 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+enum{
+ Hz = 30,
+};
+char *progname = "3d01";
+
+int tdiv = Te3 / Hz;
+
+enum{
+ Cbg,
+ Cplayer,
+ Carrow,
+ Cwall,
+ Cend,
+};
+static Image *col[Cend];
+
+typedef struct Player Player;
+struct Player{
+ Foint;
+ double θ;
+};
+static Player player;
+static Rectangle wall;
+
+static void
+forward(void)
+{
+ player.x += cos(player.θ);
+ player.y += sin(player.θ);
+}
+
+static void
+backward(void)
+{
+ player.x -= cos(player.θ);
+ player.y -= sin(player.θ);
+}
+
+static void
+turnleft(void)
+{
+ player.θ -= 0.1;
+}
+
+static void
+turnright(void)
+{
+ player.θ += 0.1;
+}
+
+static void
+transleft(void)
+{
+ player.x += sin(player.θ);
+ player.y -= cos(player.θ);
+}
+
+static void
+transright(void)
+{
+ player.x -= sin(player.θ);
+ player.y += cos(player.θ);
+}
+
+Key keys[] = {
+ {'w', forward},
+ {'s', backward},
+ {'a', turnleft},
+ {'d', turnright},
+ {'q', transleft},
+ {'e', transright},
+};
+int nkeys = nelem(keys);
+
+static void
+stepsim(void)
+{
+ Key *k;
+
+ for(k=keys; k<keys+nkeys; k++)
+ if(k->down)
+ k->fn();
+}
+
+/* absolute map: global 2d topdown view */
+static void
+render(void)
+{
+ draw(fb, fb->r, col[Cbg], nil, ZP);
+ line(fb, wall.min, wall.max, 0, 0, 1, col[Cwall], ZP);
+ ellipse(fb, Pt(player.x, player.y), 2, 2, 0, col[Cplayer], ZP);
+ line(fb, Pt(player.x, player.y),
+ Pt(player.x + cos(player.θ) * 15, player.y + sin(player.θ) * 15),
+ 0, 0, 0, col[Carrow], ZP);
+}
+
+static void
+initrender(void)
+{
+ col[Cbg] = display->black;
+ col[Cplayer] = display->white;
+ col[Carrow] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x777777ff);
+ col[Cwall] = eallocimage(Rect(0,0,1,1), screen->chan, 1, DYellow);
+}
+
+static void
+initsim(void)
+{
+ wall = Rect(70, 20, 70, 70);
+ player = (Player){(Foint){50, 50}, 0};
+}
+
+void
+threadmain(int, char**)
+{
+ sysinit(initrender, initsim, render, stepsim);
+ sim();
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,29 @@
+typedef struct Key Key;
+typedef struct Foint Foint;
+
+enum{
+ Te9 = 1000000000,
+ Te6 = 1000000,
+ Te3 = 1000,
+};
+extern int tdiv;
+
+struct Key{
+ Rune r;
+ void (*fn)(void);
+ int down;
+};
+extern Key keys[];
+extern int nkeys;
+
+extern Image *fb;
+extern Rectangle fbr;
+
+struct Foint{
+ double x;
+ double y;
+};
+
+extern char *progname;
+extern void (*renderfn)(void);
+extern void (*stepsimfn)(void);
--- /dev/null
+++ b/drw.c
@@ -1,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+Rectangle fbr;
+Image *fb;
+
+void (*renderfn)(void);
+
+Image *
+eallocimage(Rectangle r, ulong chan, int repl, ulong col)
+{
+ Image *i;
+
+ if((i = allocimage(display, r, chan, repl, col)) == nil)
+ sysfatal("allocimage: %r");
+ return i;
+}
+
+void
+updatedraw(void)
+{
+ renderfn();
+ draw(screen, screen->r, fb, nil, ZP);
+ flushimage(display, 1);
+}
+
+void
+redraw(void)
+{
+ updatedraw();
+}
+
+void
+resetdraw(void)
+{
+ freeimage(fb);
+ fbr = rectsubpt(screen->r, screen->r.min);
+ fb = eallocimage(fbr, screen->chan, 0, DNofill);
+ redraw();
+}
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,7 @@
+void* emalloc(ulong);
+void sim(void);
+void sysinit(void (*)(void), void (*)(void), void (*)(void), void (*)(void));
+Image* eallocimage(Rectangle, ulong, int, ulong);
+void updatedraw(void);
+void redraw(void);
+void resetdraw(void);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,12 @@
+</$objtype/mkfile
+TARG=\
+ 3d01\
+
+OFILES=\
+ drw.$O\
+ sys.$O\
+
+HFILES=dat.h fns.h
+</sys/src/cmd/mkmany
+BIN=$home/bin/$objtype
+HFILES=
--- /dev/null
+++ b/sys.c
@@ -1,0 +1,192 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include "dat.h"
+#include "fns.h"
+
+void (*stepsimfn)(void);
+
+typedef struct Kev Kev;
+typedef struct Mev Mev;
+struct Kev{
+ int down;
+ Rune r;
+};
+struct Mev{
+ Point;
+ int dx;
+ int dy;
+ int b;
+};
+static Channel *reszc, *kc, *mc, *tmc;
+
+void *
+emalloc(ulong n)
+{
+ void *p;
+
+ if((p = mallocz(n, 1)) == nil)
+ sysfatal("emalloc: %r");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+static void
+mproc(void *)
+{
+ int n, fd, nerr;
+ char buf[1+5*12];
+ Mev m, om;
+
+ if((fd = open("/dev/mouse", OREAD)) < 0)
+ sysfatal("mproc: %r");
+ nerr = 0;
+ memset(&om, 0, sizeof om);
+ for(;;){
+ if((n = read(fd, buf, sizeof buf)) != 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[0]){
+ case 'r': send(reszc, nil); /* wet floor */
+ case 'm':
+ 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;
+ if((m.b & 1) == 1 && (om.b & 1) == 0
+ || (m.b & 4) == 4 && (om.b & 4) == 0
+ || m.b & 2)
+ send(mc, &m);
+ om = m;
+ break;
+ }
+ }
+}
+
+static void
+kproc(void *)
+{
+ int n, fd;
+ char buf[256], down[128], *s, *p;
+ Rune r;
+ Kev ke;
+
+ if((fd = open("/dev/kbd", OREAD)) < 0)
+ sysfatal("kproc: %r");
+ memset(buf, 0, sizeof buf);
+ 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)
+ break;
+ buf[n-1] = 0;
+ buf[n] = 0;
+ }
+ switch(buf[0]){
+ default: continue;
+ case 'k': s = buf+1; p = down+1; ke.down = 1; break;
+ case 'K': s = down+1; p = buf+1; ke.down = 0; break;
+ }
+ while(*s != 0){
+ s += chartorune(&r, s);
+ if(utfrune(p, r) == nil){
+ ke.r = r;
+ if(send(kc, &ke) < 0)
+ break;
+ }
+ }
+ strcpy(down, buf);
+ }
+}
+
+static void
+timeproc(void *)
+{
+ for(;;){
+ sleep(tdiv);
+ nbsendul(tmc, 0);
+ }
+}
+
+
+void
+sim(void)
+{
+ Kev ke;
+ Mev me;
+ Key *k;
+
+ enum{
+ Aresize,
+ Amouse,
+ Akbd,
+ Atic,
+ };
+ Alt a[] = {
+ {reszc, nil, CHANRCV},
+ {mc, &me, CHANRCV},
+ {kc, &ke, CHANRCV},
+ {tmc, nil, CHANRCV},
+ {nil, nil, CHANEND}
+ };
+ for(;;){
+ switch(alt(a)){
+ case Aresize:
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");
+ resetdraw();
+ break;
+ case Amouse:
+ break;
+ case Akbd:
+ if(ke.r == Kdel)
+ threadexitsall(nil);
+ for(k=keys; k<keys+nkeys; k++)
+ if(ke.r == k->r){
+ k->down = ke.down;
+ break;
+ }
+ break;
+ case Atic:
+ stepsimfn();
+ updatedraw();
+ break;
+ }
+ }
+}
+
+void
+sysinit(void (*initrender)(void), void (*initsim)(void), void (*render)(void), void (*stepsim)(void))
+{
+ srand(time(nil));
+ if(initdraw(nil, nil, progname) < 0)
+ sysfatal("initdraw: %r");
+ if((reszc = chancreate(sizeof(int), 2)) == nil
+ || (kc = chancreate(sizeof(Kev), 20)) == nil
+ || (mc = chancreate(sizeof(Mev), 20)) == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(kproc, nil, 8192) < 0
+ || proccreate(mproc, nil, 8192) < 0)
+ sysfatal("proccreate: %r");
+ if((tmc = chancreate(sizeof(ulong), 0)) == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(timeproc, nil, 8192) < 0)
+ sysfatal("init: %r");
+ initrender();
+ initsim();
+ renderfn = render;
+ stepsimfn = stepsim;
+ resetdraw();
+}