diff options
Diffstat (limited to 'fs.c')
-rw-r--r-- | fs.c | 418 |
1 files changed, 327 insertions, 91 deletions
@@ -4,37 +4,104 @@ #include <thread.h> #include <draw.h> #include <memdraw.h> +#include <geometry.h> #include <fcall.h> #include <9p.h> +#include "libobj/obj.h" +#include "libgraphics/graphics.h" typedef struct Dirtab Dirtab; +typedef struct Client Client; struct Dirtab { char *name; - uchar type; - uint qidpath; uint perm; }; +struct Client +{ + ulong slot; + int inuse; + Camera *cam; +}; + enum { Qroot, + Qnew, + Qn, Qctl, Qframe, + Qscene, }; +#define QPATH(type, slot) (((slot)<<8)|(type)) +#define QTYPE(path) ((path)&0xFF) +#define SLOT(path) ((path)>>8) + char Ebotch[] = "9P protocol botch"; -char Enotfound[] = "file not found"; +char Enotfound[] = "file does not exist"; char Enotdir[] = "not a directory"; char Eperm[] = "permission denied"; Dirtab dirtab[] = { - "/", QTDIR, Qroot, 0555|DMDIR, - "ctl", QTFILE, Qctl, 0600, - "frame", QTFILE, Qframe, 0444, + [Qroot] "/", DMDIR|0555, + [Qnew] "new", 0666, + [Qn] nil, DMDIR|0555, + [Qctl] "ctl", 0666, + [Qframe] "frame", 0444, + [Qscene] "scene", 0666, }; char *jefe = "Pablo R. Picasso"; -Memimage *fb; +Renderer *renderer; +Client *clients; +ulong nclients; + +static LightSource light = {{0,100,100,1}, {1,1,1,1}, LIGHT_POINT}; + +static Point3 +vshader(VSparams *sp) +{ + Client *c; + Point3 pos, lightdir; + double intens; + + c = &clients[0]; + + pos = model2world(sp->su->entity, sp->v->p); + lightdir = normvec3(subpt3(light.p, pos)); + intens = fmax(0, dotvec3(sp->v->n, lightdir)); + addvattr(sp->v, "intensity", VANumber, &intens); + if(sp->v->mtl != nil){ + sp->v->c.r = sp->v->mtl->Kd.r; + sp->v->c.g = sp->v->mtl->Kd.g; + sp->v->c.b = sp->v->mtl->Kd.b; + sp->v->c.a = 1; + } + return world2clip(c->cam, pos); +} + +static Color +fshader(FSparams *sp) +{ + Color tc, c; + + if(sp->v.mtl != nil && sp->v.mtl->map_Kd != nil && sp->v.uv.w != 0) + tc = texture(sp->v.mtl->map_Kd, sp->v.uv, neartexsampler); + else if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) + tc = texture(sp->su->entity->mdl->tex, sp->v.uv, neartexsampler); + else + tc = Pt3(1,1,1,1); + + c.a = fclamp(sp->v.c.a*tc.a, 0, 1); + c.b = fclamp(sp->v.c.b*tc.b, 0, 1); + c.g = fclamp(sp->v.c.g*tc.g, 0, 1); + c.r = fclamp(sp->v.c.r*tc.r, 0, 1); + + return c; +} + +Shadertab auxshaders = {"ident", vshader, fshader}; static int mode2perm(int m) @@ -44,30 +111,89 @@ mode2perm(int m) return perms[m&OMASK]; } +static ulong +newclient(void) +{ + Client *c; + int i; + + for(i = 0; i < nclients; i++) + if(!clients[i].inuse) + return i; + + if(nclients%16 == 0) + clients = erealloc9p(clients, (nclients+16)*sizeof(*clients)); + + c = &clients[nclients++]; + c->slot = c-clients; + c->inuse = 1; + c->cam = emalloc9p(sizeof *c->cam); + c->cam->rctl = renderer; + placecamera(c->cam, Pt3(0,0,100,1), Pt3(0,0,0,1), Vec3(0,1,0)); + c->cam->s = newscene(nil); + return c->slot; +} + +static Client * +getclient(ulong slot) +{ + if(slot >= nclients) + return nil; + return &clients[slot]; +} + static void -fillstat(Dir *dir, Dirtab *d) +closeclient(Client *c) { - dir->name = estrdup9p(d->name); - dir->uid = estrdup9p(jefe); - dir->gid = estrdup9p(jefe); - dir->mode = d->perm; - dir->length = 0; - dir->qid = (Qid){d->qidpath, 0, d->type}; - dir->atime = time(0); - dir->mtime = time(0); - dir->muid = estrdup9p(""); + c->inuse = 0; +} + +static void +fillstat(Dir *d, uvlong path) +{ + Dirtab *t; + + t = &dirtab[QTYPE(path)]; + if(t->name != nil) + d->name = estrdup9p(t->name); + else{ + d->name = smprint("%llud", SLOT(path)); + if(d->name == nil) + sysfatal("smprint: %r"); + } + d->uid = estrdup9p(jefe); + d->gid = estrdup9p(jefe); + d->muid = nil; + d->atime = d->mtime = time(0); + d->length = 0; + d->mode = t->perm; + d->qid = (Qid){path, 0, t->perm>>24}; } static int -dirgen(int n, Dir *dir, void*) +rootgen(int i, Dir *d, void*) { - if(++n >= nelem(dirtab)) + if(++i >= Qn+nclients) return -1; - fillstat(dir, &dirtab[n]); + fillstat(d, i < Qn? i: QPATH(Qn, i-Qn)); return 0; } static int +clientgen(int i, Dir *d, void *aux) +{ + Client *c; + + c = aux; + i += Qn+1; + if(i < nelem(dirtab)){ + fillstat(d, QPATH(i, c->slot)); + return 0; + } + return -1; +} + +static int readimg(Memimage *i, char *t, Rectangle r, int offset, int n) { int ww, oo, y, m; @@ -108,30 +234,78 @@ fsattach(Req *r) return; } - r->ofcall.qid = (Qid){Qroot, 0, QTDIR}; - r->fid->qid = r->ofcall.qid; - r->fid->aux = nil; + r->fid->qid = (Qid){Qroot, 0, QTDIR}; + r->ofcall.qid = r->fid->qid; respond(r, nil); } +char * +fswalk1(Fid *f, char *name, Qid *qid) +{ + char buf[32]; + uvlong path; + ulong n; + int i; + + path = f->qid.path; + switch(QTYPE(path)){ + case Qroot: + if(strcmp(name, "..") == 0){ + *qid = f->qid; + return nil; + } + for(i = 1; i <= Qn; i++){ + if(i == Qn){ + n = strtoul(name, nil, 10); + snprint(buf, sizeof buf, "%lud", n); + if(n < nclients && strcmp(buf, name) == 0){ + *qid = (Qid){QPATH(Qn, n), 0, dirtab[Qn].perm>>24}; + f->qid = *qid; + return nil; + } + break; + } + 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; + case Qn: + if(strcmp(name, "..") == 0){ + *qid = (Qid){Qroot, 0, QTDIR}; + return nil; + } + 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; + } + } + default: + return Enotdir; + } +} + void fsopen(Req *r) { - int i, perm, want; - - for(i = 0; i < nelem(dirtab); i++) - if(r->fid->qid.path == dirtab[i].qidpath) - break; + Dirtab *t; + uvlong path; + int perm, want; - if(i < nelem(dirtab)){ - if(strcmp(r->fid->uid, jefe) == 0) - perm = dirtab[i].perm>>6; - else - perm = dirtab[i].perm; - }else{ + path = r->fid->qid.path; + if(QTYPE(path) >= nelem(dirtab)){ respond(r, Ebotch); return; - }; + } + t = &dirtab[QTYPE(path)]; + + perm = t->perm; + if(strcmp(r->fid->uid, jefe) == 0) + perm >>= 6; if((r->ifcall.mode & (OTRUNC|OCEXEC|ORCLOSE)) != 0) goto deny; @@ -141,33 +315,49 @@ deny: respond(r, Eperm); return; } + + if(QTYPE(path) == Qnew){ + path = QPATH(Qctl, newclient()); + r->fid->qid.path = path; + r->ofcall.qid.path = path; + } respond(r, nil); } void fsread(Req *r) { + Client *c; Memimage *i; - char buf[128], cbuf[30], *t; + char buf[1024], cbuf[30], *t; + uvlong path; ulong off, cnt; int n; + path = r->fid->qid.path; off = r->ifcall.offset; cnt = r->ifcall.count; + c = &clients[SLOT(path)]; - switch(r->fid->qid.path){ + switch(QTYPE(path)){ default: respond(r, "bug in fsread"); break; case Qroot: - dirread9p(r, dirgen, nil); + dirread9p(r, rootgen, nil); + respond(r, nil); + break; + case Qn: + dirread9p(r, clientgen, &clients[SLOT(path)]); respond(r, nil); break; case Qctl: + snprint(buf, sizeof buf, "%llud", SLOT(path)); + readstr(r, buf); respond(r, nil); break; case Qframe: - i = fb; + i = c->cam->vp->getfb(c->cam->vp)->cb; if(off < 5*12){ n = snprint(buf, sizeof buf, "%11s %11d %11d %11d %11d ", chantostr(cbuf, i->chan), @@ -207,19 +397,34 @@ 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); + 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); + snprint(buf+n, sizeof(buf)-n, "proj %s\n", c->cam->projtype == PERSPECTIVE? "persp": "ortho"); + readstr(r, buf); + respond(r, nil); + break; } } void fswrite(Req *r) { + Client *c; + Model *model; + Entity *ent; char *msg, *f[10]; + uvlong path; ulong cnt, nf; - int i; + path = r->fid->qid.path; cnt = r->ifcall.count; + c = &clients[SLOT(path)]; - switch(r->fid->qid.path){ + switch(QTYPE(path)){ default: respond(r, "bug in fswrite"); break; @@ -227,9 +432,63 @@ fswrite(Req *r) msg = emalloc9p(cnt+1); memmove(msg, r->ifcall.data, cnt); msg[cnt] = 0; + nf = tokenize(msg, f, nelem(f)); - for(i = 0; i < nf; i++) - fprint(2, "%s[%d]%s%s", i == 0? "": " ", i, f[i], i == nf-1? "\n": ""); + if(nf == 3 && strcmp(f[0], "viewport") == 0){ + /* viewport $width $height */ + if(c->cam->vp != nil) + rmviewport(c->cam->vp); + c->cam->vp = mkviewport(Rect(0,0,strtoul(f[1], nil, 10),strtoul(f[2], nil, 10))); + }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) + c->cam->projtype = PERSPECTIVE; + else if(strcmp(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) + c->cam->fov *= DEG; + }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); + }else if(nf == 1 && strcmp(f[0], "shoot")) + /* shoot */ + shootcamera(c->cam, &auxshaders); + + free(msg); + r->ofcall.count = cnt; + respond(r, nil); + break; + case Qscene: + msg = emalloc9p(cnt+1); + memmove(msg, r->ifcall.data, cnt); + msg[cnt] = 0; + + nf = tokenize(msg, f, nelem(f)); + if(nf != 1) + goto noscene; + fprint(2, "loading obj from %s", msg); + /* TODO load an actual scene (format tbd) */ + model = newmodel(); + if((model->obj = objparse(f[0])) == nil){ + delmodel(model); + goto noscene; + } + refreshmodel(model); + ent = newentity(model); + c->cam->s->addent(c->cam->s, ent); +noscene: free(msg); r->ofcall.count = cnt; respond(r, nil); @@ -240,55 +499,35 @@ fswrite(Req *r) void fsstat(Req *r) { - int i; - - for(i = 0; i < nelem(dirtab); i++) - if(r->fid->qid.path == dirtab[i].qidpath){ - fillstat(&r->d, &dirtab[i]); - respond(r, nil); - return; - } - respond(r, Enotfound); + fillstat(&r->d, r->fid->qid.path); + respond(r, nil); } -char * -fswalk1(Fid *f, char *name, Qid *qid) +void +fsdestroyfid(Fid *f) { - int i; + uvlong path; - switch(f->qid.path){ - case Qroot: - if(strcmp(name, "..") == 0){ - *qid = f->qid; - return nil; - } - for(i = 1; i < nelem(dirtab); i++) - if(strcmp(name, dirtab[i].name) == 0){ - *qid = (Qid){dirtab[i].qidpath, 0, 0}; - f->qid = *qid; - return nil; - } - return Enotfound; - default: - return Enotdir; - } + path = f->qid.path; + if(f->omode != -1 && QTYPE(path) >= Qn) + closeclient(&clients[SLOT(path)]); } -char * -fsclone(Fid *old, Fid *new) +void +fsending(Srv*) { - USED(old, new); - return nil; + threadexitsall(nil); } Srv fs = { - .attach = fsattach, - .open = fsopen, - .read = fsread, - .write = fswrite, - .stat = fsstat, - .walk1 = fswalk1, - .clone = fsclone, + .attach = fsattach, + .walk1 = fswalk1, + .open = fsopen, + .read = fsread, + .write = fswrite, + .stat = fsstat, + .destroyfid = fsdestroyfid, + .end = fsending, }; void @@ -302,10 +541,10 @@ void threadmain(int argc, char *argv[]) { char *srvname, *mtpt; - int fd; srvname = "render"; mtpt = "/mnt/render"; + GEOMfmtinstall(); ARGBEGIN{ case 'D': chatty9p++; @@ -323,14 +562,11 @@ threadmain(int argc, char *argv[]) jefe = getuser(); - fd = open("/dev/window", OREAD); - if(fd < 0) - sysfatal("open: %r"); - fb = readmemimage(fd); - if(fb == nil) - sysfatal("readmemimage: %r"); - close(fd); + if(memimageinit() != 0) + sysfatal("memimageinit: %r"); + if((renderer = initgraphics()) == nil) + sysfatal("initgraphics: %r"); threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE); - exits(nil); + threadexits(nil); } |