ref: b079d708225b49908129e3ea54d1bb80c004b25f
dir: /fs.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <draw.h> #include "dat.h" #include "fns.h" s32int sintab[256]; char **basestr; int nfontmap; uchar *fontmap; int nglyph; Pic *dfont; int nwalls; Wall *walls; int nsprites; Sprite *sprites; static Biobuf * eopen(char *s, int mode) { Biobuf *bf; if((bf = Bopen(s, mode)) == nil) sysfatal("Bopen: %r"); Blethal(bf, nil); return bf; } static long eread(Biobuf *bf, void *buf, long n) { if(Bread(bf, buf, n) != n) sysfatal("ebread: short read: %r"); return n; } static vlong bsize(Biobuf *bf) { vlong n; Dir *d; d = dirfstat(Bfildes(bf)); if(d == nil) sysfatal("bstat: %r"); n = d->length; free(d); return n; } static u8int get8(Biobuf *bf) { u8int v; eread(bf, &v, 1); return v; } static u16int get16(Biobuf *bf) { u16int v; v = get8(bf); return v | get8(bf) << 8; } static u32int get24(Biobuf *bf) { u32int v; v = get16(bf); return v | get8(bf) << 16; } static u32int get32(Biobuf *bf) { u32int v; v = get16(bf); return v | get16(bf) << 16; } static void loadpic(char *name, Pic *pic) { int fd, n, m, dx, dy; uchar *b, *s; u32int *p; Image *i; if((fd = open(name, OREAD)) < 0) sysfatal("loadpic: %r"); if((i = readimage(display, fd, 0)) == nil) sysfatal("readimage: %r"); close(fd); if(i->chan != RGBA32) sysfatal("loadpic %s: inappropriate image format", name); dx = Dx(i->r); dy = Dy(i->r); n = dx * dy; if(dx * dy > Vw * Vfullh) sysfatal("loadpic %s: inappropriate image size", name); p = emalloc(n * sizeof *p); pic->p = p; pic->w = dx; pic->h = dy; m = i->depth / 8; b = emalloc(n * m); unloadimage(i, i->r, b, n * m); freeimage(i); s = b; while(n-- > 0){ *p++ = s[0] << 24 | s[3] << 16 | s[2] << 8 | s[1]; s += m; } free(b); } static void loadfont(void) { int i, n, nx, ny; u32int *d, *s; Pic pic, *pp; loadpic("a.bit", &pic); nx = pic.w / Vfntpicw; ny = pic.h / Vfnth; if(pic.w % nx != 0 || pic.h % ny != 0) sysfatal("loadfont: invalid font pic"); nglyph = nx * ny; dfont = emalloc(nglyph * sizeof *dfont); for(i=0, pp=dfont; pp<dfont+nglyph; pp++, i++){ pp->w = Vfntw; pp->h = Vfnth; pp->p = emalloc(pp->w * pp->h * sizeof *pp->p); d = pp->p; s = pic.p + i / nx * pic.w * pp->h + i % nx * Vfntpicw + Vfntspc; for(n=0; n<pp->h; n++){ memcpy(d, s, pp->w * sizeof *d); d += pp->w; s += pic.w; } } free(pic.p); } void loadpics(void) { loadpic("b.bit", pics + PCarrow); loadpic("c.bit", pics + PCspace); loadpic("d.bit", pics + PCgrid); loadpic("e.bit", pics + PCplanets); loadpic("f.bit", pics + PCship); loadpic("k.bit", pics + PChud); loadpic("l.bit", pics + PCface); loadpic("m.bit", pics + PCammo); loadpic("n.bit", pics + PChit); loadpic("o.bit", pics + PCdir); loadpic("p.bit", pics + PCcur); loadpic("q.bit", pics + PCscroll); loadpic("r.bit", pics + PCgibs); loadfont(); canvas.p = emalloc(Vw * Vfullh * sizeof *canvas.p); canvas.w = Vw; canvas.h = Vfullh; } static void loadpal(void) { int n; u8int r, g, b; u32int *p; Biobuf *bf; bf = eopen("palettes.bin", OREAD); npal = get32(bf) / 2; if(npal % Npalcol != 0) sysfatal("loadpal: invalid palette size %d\n", npal); pal = emalloc(npal * sizeof *pal); for(p=pal; p<pal+npal; p++){ n = get16(bf); r = n & 0x1f; r = r << 3 | r >> 2; g = n >> 5 & 0x3f; g = g << 2 | g >> 4; b = n >> 11 & 0x1f; b = b << 3 | b >> 2; *p = 0xff << 24 | r << 16 | g << 8 | b; } npal /= Npalcol; Bterm(bf); } static char ** loadstr(char *name, int *nel) { int n; char **s, **p, **e, *q; Biobuf *bf; bf = eopen(name, OREAD); n = get16(bf); s = emalloc(n * sizeof *p); e = s + n; *nel = n; for(p=s; p<e; p++){ n = get16(bf); *p = emalloc(n + 1); eread(bf, *p, n); /* FIXME: not always? */ q = *p; while((q = strchr(q, '|')) != nil) *q = '\n'; } Bterm(bf); return s; } static void unpackspr(Sprite *s, Biobuf *btex, Biobuf *bshp) { int n, B, b, i, v; u32int *p; v = -1; for(i=0; i<s->w; i++){ p = s->p + i; n = s->h; while(n > 0){ B = n > 8 ? 8 : n; n -= B; b = get8(bshp); while(B > 0){ if(b & 1){ if(v >= 0){ *p = v & 15; v = -1; }else{ v = get8(btex); *p = v & 15; v >>= 4; } }else *p = -1; p += s->w; b >>= 1; B--; } } } } static void dumpbwwalls(Wall *wbuf, int nbuf) { int n, fd; char name[32], c[9]; Wall *w; for(w=wbuf; w<wbuf+nbuf; w++){ snprint(name, sizeof name, "wall%02zd.bit", w-walls); if((fd = create(name, OWRITE, 0644)) < 0) sysfatal("dumpbwwalls: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chantostr(c, GREY8), 0, 0, Wallsz, Wallsz); for(n=0; n<nelem(w->p); n++){ c[0] = w->p[n] & 0xff; write(fd, c, 1); } close(fd); } } static void dumpbwspr(Sprite *sbuf, int nbuf) { int n, fd; char name[32], c[9]; Sprite *s; for(s=sbuf; s<sbuf+nbuf; s++){ snprint(name, sizeof name, "spr%02zd.bit", s-sbuf); if((fd = create(name, OWRITE, 0644)) < 0) sysfatal("dumpbwspr: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chantostr(c, GREY8), 0, 0, s->w, s->h); for(n=0; n<s->w*s->h; n++){ c[0] = 96 * (s->p[n] & 0xff) / 16; write(fd, c, 1); } close(fd); } } static void dumpspr(Sprite *sbuf, int nbuf) { int fd; char name[32], c[9]; Sprite *s; for(s=sbuf; s<sbuf+nbuf; s++){ snprint(name, sizeof name, "spr%02zd.bit", s-sbuf); if((fd = create(name, OWRITE, 0644)) < 0) sysfatal("dumpspr: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chantostr(c, ARGB32), 0, 0, s->w, s->h); write(fd, s->p, s->w * s->h * sizeof *s->p); close(fd); } } static void dumppal(void) { int fd; char name[32], c[9]; snprint(name, sizeof name, "pal.bit"); if((fd = create(name, OWRITE, 0644)) < 0) sysfatal("dumppal: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chantostr(c, ARGB32), 0, 0, 16, npal); write(fd, pal, npal * Npalcol * sizeof *pal); close(fd); } static int loadblankspr(Sprite **sbuf, int *nsbuf, int **shpofs) { int nbuf, nspan, spansz, bshpsz, bsize, ofs, *ofsbuf, *o; Biobuf *btex, *bshp; Sprite *s, *buf; btex = eopen("stexels.bin", OREAD); get32(btex); bshp = eopen("bitshapes.bin", OREAD); bshpsz = get32(bshp); nbuf = 0; buf = nil; s = nil; ofsbuf = nil; o = nil; ofs = 0; while(bshpsz > 0){ if(s >= buf + nbuf){ buf = erealloc(buf, (nbuf+32) * sizeof *buf, nbuf * sizeof *buf); ofsbuf = erealloc(ofsbuf, (nbuf+32) * sizeof *ofsbuf, nbuf * sizeof *ofsbuf); s = buf + nbuf; o = ofsbuf + nbuf; nbuf += 32; } get16(bshp); get16(bshp); bsize = get16(bshp) + 8; get16(bshp); s->r.min.x = get8(bshp); s->r.max.x = get8(bshp); s->r.min.y = get8(bshp); s->r.max.y = get8(bshp); nspan = Dx(s->r) + 1; spansz = Dy(s->r) + 1; s->w = nspan; s->h = spansz; s->p = emalloc(s->w * s->h * sizeof *s->p); unpackspr(s, btex, bshp); s++; *o++ = ofs; ofs += bsize; bshpsz -= bsize; } if(bshpsz != 0){ werrstr("sprite data and shape mismatch by %d bytes", bshpsz); return -1; } *sbuf = buf; *nsbuf = s - buf; *shpofs = ofsbuf; Bterm(btex); Bterm(bshp); return 0; } static int gencolorspr(Sprite *sbuf, int nbuf, int *shpofs) { int *shp; u32int n, ofs, palofs, *pp, *bp, *p; Biobuf *bf; Sprite *s, *bw; bf = eopen("mappings.bin", OREAD); ofs = get32(bf) * 2 * sizeof(u32int); n = get32(bf); get32(bf); get32(bf); Bseek(bf, ofs, 1); sprites = emalloc(n * sizeof *sprites); nsprites = n; for(s=sprites; s<sprites+nsprites; s++){ ofs = get32(bf); palofs = get32(bf); if(palofs % Npalcol != 0 || palofs / Npalcol >= npal){ werrstr("gencolorspr: invalid palette index %ud", palofs); return -1; } for(shp=shpofs; shp<shpofs+nbuf; shp++) if(*shp == ofs) break; if(shp >= shpofs+nbuf){ werrstr("gencolorspr: invalid bitshapes offset %ud", ofs); return -1; } bw = sbuf + (shp - shpofs); pp = pal + palofs; memcpy(s, bw, sizeof *s); s->p = emalloc(s->w * s->h * sizeof *s->p); for(p=s->p, bp=bw->p; p<s->p+s->w*s->h; p++, bp++){ n = *bp; if(n == -1UL) *p = 0; else if(n > Npalcol){ werrstr("gencolor: invalid palette color index %ud", n); return -1; }else *p = pp[n]; } } Bterm(bf); return 0; } static void loadsprites(void) { int nbuf, *shpofs; Sprite *sbuf, *s; sbuf = nil; nbuf = 0; shpofs = nil; if(loadblankspr(&sbuf, &nbuf, &shpofs) < 0 || gencolorspr(sbuf, nbuf, shpofs) < 0) sysfatal("loadsprites: %r"); for(s=sbuf; s<sbuf+nbuf; s++) free(s->p); free(sbuf); free(shpofs); } static void loadwalls(void) { int i, j, n, v; Biobuf *bf; Wall *w, *we; u32int *p; bf = eopen("wtexels.bin", OREAD); n = get32(bf) / (Wallsz * Wtexelsz); walls = emalloc(n * sizeof *walls); nwalls = n; for(w=walls, we=w+n; w<we; w++){ for(i=0; i<Wallsz; i++){ p = w->p + i; for(j=0; j<Wtexelsz; j++){ v = get8(bf); *p = v & 15; p += Wallsz; *p = v >> 4 & 15; p += Wallsz; } } } Bterm(bf); } static void loadfontmap(void) { int n; Biobuf *bf; bf = eopen("a.map", OREAD); n = bsize(bf); fontmap = emalloc(n * sizeof *fontmap); eread(bf, fontmap, n); nfontmap = n; Bterm(bf); } static void loadbasestr(void) { int nel; basestr = loadstr("base.str", &nel); if(nel != BSend) sysfatal("loadbasestr: inconsistent base.str file: entries %d not %d", nel, BSend); } static void dumpbspnodes(Map *m) { int ni, fd; char path[64], s[32]; Point p; Font *f; Image *i, *b, *c, *o; Line *l, *le; Node *n; assert(display != nil); b = eallocimage(Rect(0,0,256<<2,256<<2), 0, DBlack); i = eallocimage(b->r, 0, DNofill); c = eallocimage(Rect(0,0,1,1), 1, DRed); o = eallocimage(Rect(0,0,1,1), 1, 0x777777FF); if((f = openfont(display, "/lib/font/bit/fixed/unicode.6x10.font")) == nil) sysfatal("openfont: %r"); for(l=m->lines; l<m->lines+m->nlines; l++) line(b, divpt(l->min,2), divpt(l->max,2), 0, Endarrow, 0, display->white, ZP); for(n=m->nodes, ni=0; n<m->nodes+m->nnodes; n++){ draw(i, i->r, b, nil, ZP); draw(i, Rpt(divpt(n->min,2), divpt(n->max,2)), o, nil, ZP); switch(n->type){ case 0: l = m->lines + n->right; le = l + n->left; for(; l<le; l++){ line(i, divpt(l->min,2), divpt(l->max,2), 0, Endarrow, 0, c, ZP); p.x = (l->min.x + Dx(l->Rectangle) / 2) / 2; p.y = (l->min.y + Dy(l->Rectangle) / 2) / 2; snprint(s, sizeof s, "%zd", l - (m->lines+n->right)); string(i, p, c, ZP, f, s); } break; case 1: line(i, Pt(0,n->split/2), Pt(i->r.max.x,n->split/2), 0, 0, 0, c, ZP); line(i, divpt(n->min,2), divpt(n->max,2), 0, Endarrow, 0, c, ZP); p.x = (n->min.x + Dx(n->Rectangle) / 2) / 2; p.y = (n->min.y + Dy(n->Rectangle) / 2) / 2; snprint(s, sizeof s, "%zd → %d,%d", n-m->nodes, n->left, n->right); string(i, p, c, ZP, f, s); break; case 2: line(i, Pt(n->split/2,0), Pt(n->split/2,i->r.max.y), 0, 0, 0, c, ZP); line(i, divpt(n->min,2), divpt(n->max,2), 0, Endarrow, 0, c, ZP); p.x = (n->min.x + Dx(n->Rectangle) / 2) / 2; p.y = (n->min.y + Dy(n->Rectangle) / 2) / 2; snprint(s, sizeof s, "%zd → %d,%d", n-m->nodes, n->left, n->right); string(i, p, c, ZP, f, s); break; default: sysfatal("unknown node type %d\n", n->type); } snprint(path, sizeof path, "node%04d.bit", ni++); if((fd = create(path, OWRITE, 0664)) < 0) sysfatal("create: %r"); if(writeimage(fd, i, 0) < 0) sysfatal("writeimage: %r"); close(fd); } freeimage(b); freeimage(i); freeimage(c); freeimage(o); freefont(f); } static void dumplines(Map *m) { int fd; Image *i; Line *l; assert(display != nil); i = eallocimage(Rect(0,0,256<<3,256<<3), 0, DBlack); for(l=m->lines; l<m->lines+m->nlines; l++) line(i, l->min, l->max, 0, Endarrow, 0, display->white, ZP); if((fd = create("lines.bit", OWRITE, 0664)) < 0) sysfatal("create: %r"); if(writeimage(fd, i, 0) < 0) sysfatal("writeimage: %r"); freeimage(i); close(fd); } static void loadbsp(Biobuf *bf, Map *m) { Node *n; m->nnodes = get16(bf); m->nodes = emalloc(m->nnodes * sizeof *m->nodes); for(n=m->nodes; n<m->nodes+m->nnodes; n++){ n->min.x = get8(bf) << Fineshift; n->min.y = get8(bf) << Fineshift; n->max.x = get8(bf) << Fineshift; n->max.y = get8(bf) << Fineshift; n->type = get8(bf); n->split = get8(bf) << Fineshift; n->left = get16(bf); n->right = get16(bf); } } static void loadlines(Biobuf *bf, Map *m) { Line *l; m->nlines = get16(bf); m->lines = emalloc(m->nlines * sizeof *m->lines); for(l=m->lines; l<m->lines+m->nlines; l++){ l->min.x = get8(bf) << Fineshift; l->min.y = get8(bf) << Fineshift; l->max.x = get8(bf) << Fineshift; l->max.y = get8(bf) << Fineshift; l->tex = get16(bf); /* FIXME: actual Wall* */ l->flags = get16(bf); if(l->flags & LFmirrored) l->minpshift = max(Dx(l->Rectangle), Dy(l->Rectangle)); else l->maxpshift = max(Dx(l->Rectangle), Dy(l->Rectangle)); if(l->flags & (LFxshift | LFshiftS⋁E)) l->Rectangle = rectaddpt(l->Rectangle, Pt(3,0)); else if(l->flags & (LFxshift | LFshiftN∨W)) l->Rectangle = rectsubpt(l->Rectangle, Pt(3,0)); else if(l->flags & (LFyshift | LFshiftS⋁E)) l->Rectangle = rectaddpt(l->Rectangle, Pt(0,3)); else if(l->flags & (LFyshift | LFshiftN∨W)) l->Rectangle = rectsubpt(l->Rectangle, Pt(0,3)); /* FIXME: no way to know why until we properly process walls to dump them */ if(l->tex == 7){ } /* FIXME */ } } static void loadmap(char *name) { Biobuf *bf; Map *m; bf = eopen(name, OREAD); m = ↦ m->ceilc = 0xff << 24 | get24(bf); m->floorc = 0xff << 24 | get24(bf); m->backc = 0xff << 24 | get24(bf); m->id = get8(bf); m->unkn1 = get16(bf); m->unkn2 = get8(bf); loadbsp(bf, m); loadlines(bf, m); /* FIXME: things, events, commands */ Bterm(bf); } static void loadsintab(void) { Biobuf *bf; s32int *s; bf = eopen("sintable.bin", OREAD); for(s=sintab; s<sintab+nelem(sintab); s++) *s = get32(bf); Bterm(bf); } void initfs(void) { rfork(RFNAMEG); if(bind(".", prefix, MBEFORE|MCREATE) == -1 || chdir(prefix) < 0) fprint(2, "initfs: %r\n"); loadsintab(); loadpal(); loadbasestr(); loadfontmap(); // FIXME: walls: same processing as sprites loadwalls(); loadsprites(); loadmap("intro.bsp"); }