ref: 139309e7c5cb445df58e3f3f252e3545d59558bd
parent: 7ca15d3d92fbe86ba688758f3ef07db3c787d504
author: rodri <[email protected]>
date: Wed Apr 3 10:24:27 EDT 2024
use lib9p's Cmdtab for ctl messages and sanitize its input. also provide better camera defaults.
--- a/fs.c
+++ b/fs.c
@@ -27,6 +27,23 @@
};
enum {
+ CMviewport,
+ CMmove,
+ CMprojection,
+ CMfov,
+ CMclip,
+ CMshoot,
+};
+Cmdtab cmds[] = {
+ CMviewport, "viewport", 3, /* viewport $width $height */
+ CMmove, "move", 5, /* move $subject $x $y $z */
+ CMprojection, "projection", 2, /* projection [persp|ortho] */
+ CMfov, "fov", 2, /* fov $angle */
+ CMclip, "clip", 3, /* clip [near|far] $dz */
+ CMshoot, "shoot", 1, /* shoot */
+};
+
+enum {
Qroot,
Qnew,
Qn,
@@ -43,6 +60,7 @@
char Enotfound[] = "file does not exist";
char Enotdir[] = "not a directory";
char Eperm[] = "permission denied";
+char Enoscene[] = "no scene";
Dirtab dirtab[] = {
[Qroot] "/", DMDIR|0555,
@@ -53,6 +71,7 @@
[Qscene] "scene", 0666,
};
char *jefe = "Pablo R. Picasso";
+Memsubfont *memfont;
Renderer *renderer;
Client *clients;
ulong nclients;
@@ -66,7 +85,7 @@
Point3 pos, lightdir;
double intens;
- c = &clients[0];
+ c = &clients[0]; /* TODO figure out a way to address the correct client */
pos = model2world(sp->su->entity, sp->v->p);
lightdir = normvec3(subpt3(light.p, pos));
@@ -111,6 +130,25 @@
return perms[m&OMASK];
}
+static long
+strwidth(char *s)
+{
+ long cw, nc, n;
+ Rune r;
+
+ /*
+ * memfont = defont = vga. so we can safely assume all
+ * the glyphs have the same width.
+ */
+ nc = 0;
+ cw = memfont->info->width;
+ while(*s){
+ nc += n = chartorune(&r, s);
+ s += n;
+ }
+ return cw*nc;
+}
+
static ulong
newclient(void)
{
@@ -128,12 +166,15 @@
c->slot = c-clients;
c->inuse = 1;
c->cam = emalloc9p(sizeof *c->cam);
+ c->cam->vp = mkviewport(Rect(0,0,320,200));
c->cam->fov = 40*DEG;
c->cam->clip.n = 0.01;
c->cam->clip.f = 1000;
- placecamera(c->cam, Pt3(0,0,100,1), Pt3(0,0,0,1), Vec3(0,1,0));
+ c->cam->projtype = PERSPECTIVE;
c->cam->rctl = renderer;
c->cam->s = newscene(nil);
+ placecamera(c->cam, Pt3(0,0,100,1), Pt3(0,0,0,1), Vec3(0,1,0));
+ reloadcamera(c->cam);
return c->slot;
}
@@ -280,13 +321,13 @@
*qid = (Qid){Qroot, 0, QTDIR};
return nil;
}
- for(i = Qn+1; i < nelem(dirtab); i++){
+ for(i = Qn+1; i < nelem(dirtab); i++)
if(strcmp(name, dirtab[i].name) == 0){
*qid = (Qid){QPATH(i, SLOT(path)), 0, dirtab[i].perm>>24};
f->qid = *qid;
return nil;
}
- }
+ return Enotfound;
default:
return Enotdir;
}
@@ -331,6 +372,7 @@
fsread(Req *r)
{
Client *c;
+ Framebuf *fb;
Memimage *i;
char buf[1024], cbuf[30], *t;
uvlong path;
@@ -360,7 +402,8 @@
respond(r, nil);
break;
case Qframe:
- i = c->cam->vp->getfb(c->cam->vp)->cb;
+ fb = c->cam->vp->getfb(c->cam->vp);
+ i = fb->cb;
if(off < 5*12){
n = snprint(buf, sizeof buf, "%11s %11d %11d %11d %11d ",
chantostr(cbuf, i->chan),
@@ -401,8 +444,8 @@
free(t);
break;
case Qscene:
-// readstr(r, "no scenes\n");
- n = snprint(buf, sizeof buf, "viewport %R\n", c->cam->vp? c->cam->vp->getfb(c->cam->vp)->r: ZR);
+// snprint(buf, sizeof buf, "%s\n", Enoscene);
+ n = snprint(buf, sizeof buf, "viewport %R\n", c->cam->vp->getfb(c->cam->vp)->r);
n += snprint(buf+n, sizeof(buf)-n, "pos %V\n", c->cam->p);
n += snprint(buf+n, sizeof(buf)-n, "fov %g°\n", c->cam->fov/DEG);
n += snprint(buf+n, sizeof(buf)-n, "clip [%g %g]\n", c->cam->clip.n, c->cam->clip.f);
@@ -419,10 +462,15 @@
Client *c;
Model *model;
Entity *ent;
- char *msg, *f[10];
+ Framebuf *fb;
+ Cmdbuf *cb;
+ Cmdtab *ct;
+ Point pt;
+ char *msg, *f[4];
uvlong path;
- ulong cnt, nf;
- int w, h;
+ ulong cnt;
+ int nf, w, h;
+ double clipn, clipf;
path = r->fid->qid.path;
cnt = r->ifcall.count;
@@ -437,44 +485,70 @@
memmove(msg, r->ifcall.data, cnt);
msg[cnt] = 0;
- nf = tokenize(msg, f, nelem(f));
- if(nf == 3 && strcmp(f[0], "viewport") == 0){
- /* viewport $width $height */
- if(c->cam->vp != nil)
- rmviewport(c->cam->vp);
+ cb = parsecmd(msg, strlen(msg));
+ ct = lookupcmd(cb, cmds, nelem(cmds));
+ if(ct == nil)
+ goto nocmd;
- w = strtoul(f[1], nil, 10);
- h = strtoul(f[2], nil, 10);
+ switch(ct->index){
+ case CMviewport:
+ w = strtoul(cb->f[1], nil, 10);
+ h = strtoul(cb->f[2], nil, 10);
+ rmviewport(c->cam->vp);
c->cam->vp = mkviewport(Rect(0,0,w,h));
- }else if(nf == 5 && strcmp(f[0], "move") == 0 && strcmp(f[1], "camera") == 0){
- /* move camera $x $y $z */
- c->cam->p.x = strtod(f[2], nil);
- c->cam->p.y = strtod(f[3], nil);
- c->cam->p.z = strtod(f[4], nil);
- }else if(nf == 2 && strcmp(f[0], "projection") == 0){
- /* projection [persp|ortho] */
- if(strcmp(f[1], "persp") == 0)
+ break;
+ case CMmove:
+ if(strcmp(cb->f[1], "camera") == 0){
+ c->cam->p.x = strtod(cb->f[2], nil);
+ c->cam->p.y = strtod(cb->f[3], nil);
+ c->cam->p.z = strtod(cb->f[4], nil);
+ }
+ break;
+ case CMprojection:
+ if(strcmp(cb->f[1], "persp") == 0)
c->cam->projtype = PERSPECTIVE;
- else if(strcmp(f[1], "ortho") == 0)
+ else if(strcmp(cb->f[1], "ortho") == 0)
c->cam->projtype = ORTHOGRAPHIC;
reloadcamera(c->cam);
- }else if(nf == 2 && strcmp(f[0], "fov") == 0){
- /* fov $angle */
- c->cam->fov = strtod(f[1], nil);
- if(utfrune(f[1], L'°') != nil)
+ break;
+ case CMfov:
+ c->cam->fov = strtod(cb->f[1], nil);
+
+ if(utfrune(cb->f[1], L'°') != nil)
c->cam->fov *= DEG;
+
+ c->cam->fov = fclamp(c->cam->fov, 1*DEG, 180*DEG);
reloadcamera(c->cam);
- }else if(nf == 3 && strcmp(f[0], "clip") == 0){
- /* clip [near|far] $dz */
- if(strcmp(f[1], "near") == 0)
- c->cam->clip.n = strtod(f[2], nil);
- else if(strcmp(f[1], "far") == 0)
- c->cam->clip.f = strtod(f[2], nil);
+ break;
+ case CMclip:
+ clipn = c->cam->clip.n;
+ clipf = c->cam->clip.f;
+
+ if(strcmp(cb->f[1], "near") == 0)
+ clipn = strtod(cb->f[2], nil);
+ else if(strcmp(cb->f[1], "far") == 0)
+ clipf = strtod(cb->f[2], nil);
+
+ if(clipn >= clipf)
+ break;
+
+ c->cam->clip.n = clipn;
+ c->cam->clip.f = clipf;
reloadcamera(c->cam);
- }else if(nf == 1 && strcmp(f[0], "shoot") == 0)
- /* shoot */
+ break;
+ case CMshoot:
+ if(c->cam->s->nents < 1){
+ fb = c->cam->vp->getfb(c->cam->vp);
+ pt = Pt(Dx(fb->r)/2-strwidth(Enoscene)/2,Dy(fb->r)/2-memfont->height/2);
+ memimagedraw(fb->cb, fb->r, memwhite, ZP, nil, ZP, S);
+ memimagestring(fb->cb, pt, memblack, ZP, memfont, Enoscene);
+ break;
+ }
shootcamera(c->cam, &auxshaders);
-
+ break;
+ }
+nocmd:
+ free(cb);
free(msg);
r->ofcall.count = cnt;
respond(r, nil);
@@ -487,7 +561,9 @@
nf = tokenize(msg, f, nelem(f));
if(nf != 1)
goto noscene;
+
fprint(2, "loading obj from %s\n", msg);
+
/* TODO load an actual scene (format tbd) */
model = newmodel();
if((model->obj = objparse(f[0])) == nil){
@@ -575,6 +651,7 @@
sysfatal("memimageinit: %r");
if((renderer = initgraphics()) == nil)
sysfatal("initgraphics: %r");
+ memfont = getmemdefont();
threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE);
threadexits(nil);