ref: c183f656495c07f3c600a09185073a00076c2e62
dir: /dmap.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <keyboard.h> #include <mouse.h> #include "dat.h" #include "fns.h" /* FIXME: inserting/modifying vertices/things: snap to grid is essential */ /* FIXME: need a node builder to test shit */ enum{ Cbg, Cwall, Cline, Cthing, Cvert, Cgrid, Ctext, Cend, Nview = 1000, Nzoom = 300, }; static int viewdiv = Nzoom; static int grunit = 128; static int skipms, mode, join; static Image *col[Cend], *fb, *fbsel, *fbselc; static Point center, view; static Keyboardctl *kc; static Mousectl *mc; void * emalloc(ulong n) { void *p; if((p = mallocz(n, 1)) == nil) sysfatal("mallocz: %r"); setmalloctag(p, getcallerpc(&n)); return p; } Image * eallocimage(Rectangle r, ulong chan, int repl, ulong c) { Image *i; if((i = allocimage(display, r, chan, repl, c)) == nil) sysfatal("allocimage: %r"); return i; } Point viewpt(Point p) { double f; f = (double)viewdiv / Nview; p.x = view.x + p.x * f; p.y = view.y + p.y * f; return p; } Point abspt(Point p) { double f; f = (double)viewdiv / Nview; p.x = (p.x - view.x) / f; p.y = (p.y - view.y) / f; return p; } void drawgrid(void) { Point p, v; p = Pt(0, 0); for(;;){ v = viewpt(p); if(v.x >= fb->r.max.x && v.y >= fb->r.max.y) break; line(fb, Pt(0, v.y), Pt(Dx(fb->r), v.y), 0, 0, 0, col[Cgrid], ZP); line(fb, Pt(v.x, 0), Pt(v.x, Dy(fb->r)), 0, 0, 0, col[Cgrid], ZP); p.x += grunit; p.y += grunit; } p = Pt(0 - grunit, 0 - grunit); for(;;){ v = viewpt(p); if(v.x <= fb->r.min.x && v.y <= fb->r.min.y) break; line(fb, Pt(0, v.y), Pt(Dx(fb->r), v.y), 0, 0, 0, col[Cgrid], ZP); line(fb, Pt(v.x, 0), Pt(v.x, Dy(fb->r)), 0, 0, 0, col[Cgrid], ZP); p.x -= grunit; p.y -= grunit; } } void doline(Point m1, Point m2, int type, uchar *sel) { int et; Image *c; c = col[type]; et = type == Cthing && mode == 2 || type != Cthing && mode == 1 ? Endarrow : 0; line(fb, m1, m2, 0, et, 0, c, ZP); loadimage(fbselc, fbselc->r, sel, 4); line(fbsel, m1, m2, 0, et, 0, fbselc, ZP); } void doellipse(Point p, int r, int type, uchar *sel) { fillellipse(fb, p, r, r, col[type], ZP); loadimage(fbselc, fbselc->r, sel, 4); fillellipse(fbsel, p, r, r, fbselc, ZP); } void drawlines(void) { Line *l; Point m1, m2; for(l=lines; l<lines+nlines; l++){ m1 = viewpt(*l->v); m2 = viewpt(*l->w); if(!ptinrect(m1, fb->r) && !ptinrect(m2, fb->r) && !((m1.x >= 0 && m1.x < Dx(fb->r) && (m1.y < 0 || m1.y >= Dy(fb->r))) || (m2.x >= 0 && m2.x < Dx(fb->r) && (m2.y < 0 || m2.y >= Dy(fb->r))))) continue; doline(m1, m2, l->f & LFimpass ? Cwall : Cline, l->sel); } } void drawvertices(void) { Vertex *v; Point p; int r; r = mode==0 ? 2 : 1; for(v=verts; v<verts+nverts; v++){ p = viewpt(*v); if(!ptinrect(p, fb->r)) continue; doellipse(p, r, Cvert, v->sel); } } void drawthings(void) { Thing *t; Point m1, m2; for(t=things; t<things+nthings; t++){ m1 = viewpt(*t); if(!ptinrect(m1, fb->r)) continue; if(mode != 2) doellipse(m1, 1, Cthing, t->sel); else{ m2 = t->an == 0 ? (Point){m1.x+1, m1.y} : t->an == 45 ? (Point){m1.x+1, m1.y-1} : t->an == 90 ? (Point){m1.x, m1.y-1} : t->an == 135 ? (Point){m1.x-1, m1.y-1} : t->an == 180 ? (Point){m1.x-1, m1.y} : t->an == 225 ? (Point){m1.x-1, m1.y+1} : t->an == 270 ? (Point){m1.x, m1.y+1} : t->an == 315 ? (Point){m1.x+1, m1.y+1} : m1; doline(m1, m2, Cthing, t->sel); } } } void redraw(void) { draw(fb, fb->r, col[Cbg], nil, ZP); draw(fbsel, fbsel->r, col[Cbg], nil, ZP); drawgrid(); drawlines(); drawvertices(); drawthings(); string(fb, Pt(0,0), col[Ctext], Pt(0,0), font, join ? "join" : "split"); draw(screen, screen->r, fb, nil, ZP); flushimage(display, 1); } void drawstats(Point p) { char buf[128]; uchar sel[4]; u32int x; Line *l; Thing *t; Side *d; Sector *s; Vertex *v; unloadimage(fbsel, rectaddpt(fbselc->r, p), sel, sizeof sel); x = sel[3] << 24 | sel[2] << 16 | sel[1] << 8 | sel[0]; draw(screen, screen->r, fb, nil, ZP); p = abspt(p); sprint(buf, "%d,%d", p.x & ~(grunit-1), p.y & ~(grunit-1)); p = Pt(screen->r.max.x - strlen(buf) * font->width, screen->r.max.y - font->height); string(screen, p, col[Ctext], Pt(0,0), font, buf); if(x == 0) goto end; p = Pt(screen->r.min.x, screen->r.max.y - font->height * 5); switch(x & 7<<21){ case CFline: l = lines + (x & 0xffff); sprint(buf, "(%d,%d %d,%d len N) type %d tag %d", l->v->x, l->v->y, l->w->x, l->w->y, l->type, l->tag); string(screen, p, col[Ctext], Pt(0,0), font, buf); p.y += font->height; d = l->r; sprint(buf, "front: %-8s %-8s %-8s ofs %d,%d", d->high, d->mid, d->low, d->x, d->y); string(screen, p, col[Ctext], Pt(0,0), font, buf); p.y += font->height; s = d->s; sprint(buf, "floor %d %-8s ceiling %d %-8s (height %d) light %d type %d tag %d", s->x, s->fflat, s->y, s->cflat, s->y - s->x, s->lum, s->type, s->tag); string(screen, p, col[Ctext], Pt(0,0), font, buf); p.y += font->height; if((l->f & LFtwosd) == 0) goto end; d = l->l; sprint(buf, "back: %-8s %-8s %-8s ofs %d,%d", d->high, d->mid, d->low, d->x, d->y); string(screen, p, col[Ctext], Pt(0,0), font, buf); p.y += font->height; s = d->s; sprint(buf, "floor %d %-8s ceiling %d %-8s (height %d) light %d type %d tag %d", s->x, s->fflat, s->y, s->cflat, s->y - s->x, s->lum, s->type, s->tag); string(screen, p, col[Ctext], Pt(0,0), font, buf); break; case CFthing: t = things + (x & 0xffff); p.y += font->height * 4; sprint(buf, "%d,%d ∠ %d type %d flags %#08ux", t->x, t->y, t->an, t->type, t->f); string(screen, p, col[Ctext], Pt(0,0), font, buf); break; case CFvert: v = verts + (x & 0xffff); p.y += font->height * 4; sprint(buf, "%d,%d", v->x, v->y); string(screen, p, col[Ctext], Pt(0,0), font, buf); break; } end: flushimage(display, 1); } void initfb(int v) { Rectangle r; center = divpt(subpt(screen->r.max, screen->r.min), 2); if(v) view = center; r = rectsubpt(screen->r, screen->r.min); freeimage(fb); fb = eallocimage(r, screen->chan, 0, DNofill); freeimage(fbsel); fbsel = eallocimage(r, XRGB32, 0, DNofill); redraw(); skipms++; } void usage(void) { fprint(2, "%s [mapdir]\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char *argv[]) { Mouse m; Point mo; double f, vx, vy; Rune r; ARGBEGIN{ default: usage(); }ARGEND if(initdraw(nil, nil, "dmap") < 0) sysfatal("initdraw: %r"); load(*argv); if((kc = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); if((mc = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); col[Cbg] = display->black, col[Cwall] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0xccccccff); col[Cline] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x5f5f5fff); col[Cthing] = eallocimage(Rect(0,0,1,1), screen->chan, 1, DGreen); col[Cvert] = eallocimage(Rect(0,0,1,1), screen->chan, 1, DGreyblue); col[Cgrid] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x101010ff); col[Ctext] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x884400ff); fbselc = eallocimage(Rect(0,0,1,1), XRGB32, 1, DNofill); initfb(1); vx = view.x - center.x; vy = view.y - center.y; Alt a[] = { {mc->resizec, nil, CHANRCV}, {mc->c, &m, CHANRCV}, {kc->c, &r, CHANRCV}, {nil, nil, CHANEND} }; for(;;){ switch(alt(a)){ case 0: if(getwindow(display, Refnone) < 0) sysfatal("getwindow: %r"); initfb(0); break; case 1: if(skipms){ skipms = 0; goto skip; } if(m.buttons & 2){ f = (double)viewdiv / Nview; viewdiv += (m.xy.y - mo.y) / 2; if(viewdiv > 10 * Nview) viewdiv = 10 * Nview; else if(viewdiv < 1) viewdiv = 1; f = ((double)viewdiv / Nview) / f; vx *= f; vy *= f; view = addpt(center, Pt(vx, vy)); redraw(); } if(m.buttons & 1){ mo = subpt(m.xy, mo); view = addpt(view, mo); vx = view.x - center.x; vy = view.y - center.y; redraw(); } if(ptinrect(m.xy, screen->r)) drawstats(subpt(m.xy, screen->r.min)); skip: mo = m.xy; break; case 2: switch(r){ paint: redraw(); break; case Kdel: case 'q': threadexitsall(nil); case 'a': mode = (mode + 1) % 3; goto paint; case 'j': join ^= 1; goto paint; case 'r': view = center; vx = view.x - center.x; vy = view.y - center.y; goto paint; case '+': case '=': if(grunit < 1024){ grunit <<= 1; goto paint; } break; case '-': if(grunit > 1){ grunit >>= 1; goto paint; } break; case 'z': viewdiv = Nzoom; goto paint; } break; default: threadexitsall("alt: %r"); } } }