From 139309e7c5cb445df58e3f3f252e3545d59558bd Mon Sep 17 00:00:00 2001 From: rodri Date: Wed, 3 Apr 2024 14:24:27 +0000 Subject: use lib9p's Cmdtab for ctl messages and sanitize its input. also provide better camera defaults. --- fs.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 39 deletions(-) diff --git a/fs.c b/fs.c index 5bca49d..ceb69ac 100644 --- a/fs.c +++ b/fs.c @@ -26,6 +26,23 @@ struct Client Camera *cam; }; +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, @@ -43,6 +60,7 @@ char Ebotch[] = "9P protocol botch"; 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 @@ Dirtab dirtab[] = { [Qscene] "scene", 0666, }; char *jefe = "Pablo R. Picasso"; +Memsubfont *memfont; Renderer *renderer; Client *clients; ulong nclients; @@ -66,7 +85,7 @@ vshader(VSparams *sp) 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 @@ mode2perm(int m) 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 @@ newclient(void) 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 @@ fswalk1(Fid *f, char *name, Qid *qid) *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 @@ void fsread(Req *r) { Client *c; + Framebuf *fb; Memimage *i; char buf[1024], cbuf[30], *t; uvlong path; @@ -360,7 +402,8 @@ fsread(Req *r) 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 @@ fsread(Req *r) 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 @@ fswrite(Req *r) 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 @@ fswrite(Req *r) 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 @@ fswrite(Req *r) 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 @@ threadmain(int argc, char *argv[]) sysfatal("memimageinit: %r"); if((renderer = initgraphics()) == nil) sysfatal("initgraphics: %r"); + memfont = getmemdefont(); threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE); threadexits(nil); -- cgit v1.2.3