From 0373255087377122eeb10e006ffb8aa1b57e611c Mon Sep 17 00:00:00 2001 From: rgl Date: Mon, 3 Feb 2020 22:42:28 +0100 Subject: after a year or so of work, i dare create a proper repo. --- main.c | 396 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 main.c (limited to 'main.c') diff --git a/main.c b/main.c new file mode 100644 index 0000000..369c3f2 --- /dev/null +++ b/main.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include "geometry.h" +#include "graphics.h" +#include "obj.h" +#include "dat.h" +#include "fns.h" + +Rune keys[Ke] = { + [K↑] = Kup, + [K↓] = Kdown, + [K←] = Kleft, + [K→] = Kright, + [Krise] = Kpgup, + [Kfall] = Kpgdown, + [KR↑] = 'w', + [KR↓] = 's', + [KR←] = 'a', + [KR→] = 'd', + [KR↺] = 'q', + [KR↻] = 'e', + [Kcam0] = KF|1, + [Kcam1] = KF|2, + [Kcam2] = KF|3, + [Kcam3] = KF|4, + [Kscrshot] = KF|12 +}; + +char stats[Se][256]; + +Mousectl *mctl; +int kdown; +double t0, Δt; +RWLock worldlock; +Mesh model; +char *mdlpath = "../threedee/mdl/rocket.obj"; + +Camera cams[4], *maincam; + +#pragma varargck type "v" Point2 +int +vfmt(Fmt *f) +{ + Point2 p; + + p = va_arg(f->args, Point2); + return fmtprint(f, "[%g %g %g]", p.x, p.y, p.w); +} + +#pragma varargck type "V" Point3 +int +Vfmt(Fmt *f) +{ + Point3 p; + + p = va_arg(f->args, Point3); + return fmtprint(f, "[%g %g %g %g]", p.x, p.y, p.z, p.w); +} + +void * +emalloc(ulong n) +{ + void *p; + + p = malloc(n); + if(p == nil) + sysfatal("malloc: %r"); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +void * +erealloc(void *p, ulong n) +{ + void *np; + + np = realloc(p, n); + if(np == nil) + sysfatal("realloc: %r"); + setrealloctag(np, getcallerpc(&p)); + return np; +} + +int +depthcmp(void *a, void *b) +{ + Triangle3 *ta, *tb; + double za, zb; + + ta = (Triangle3 *)a; + tb = (Triangle3 *)b; + za = (ta->p0.z + ta->p1.z + ta->p2.z)/3; + zb = (tb->p0.z + tb->p1.z + tb->p2.z)/3; + return zb-za; +} + +void +drawaxis(void) +{ + Point3 op = (Point3){0, 0, 0, 1}, + px = (Point3){1, 0, 0, 1}, + py = (Point3){0, 1, 0, 1}, + pz = (Point3){0, 0, 1, 1}; + + line3(maincam, op, px, 0, Endarrow, display->black); + string3(maincam, px, display->black, font, "x"); + line3(maincam, op, py, 0, Endarrow, display->black); + string3(maincam, py, display->black, font, "y"); + line3(maincam, op, pz, 0, Endarrow, display->black); + string3(maincam, pz, display->black, font, "z"); +} + +void +drawstats(void) +{ + int i; + + snprint(stats[Scamno], sizeof(stats[Scamno]), "CAM %d", maincam-cams+1); + snprint(stats[Sfov], sizeof(stats[Sfov]), "FOV %g°", maincam->fov); + snprint(stats[Scampos], sizeof(stats[Scampos]), "%V", maincam->p); + snprint(stats[Scambx], sizeof(stats[Scambx]), "bx %V", maincam->bx); + snprint(stats[Scamby], sizeof(stats[Scamby]), "by %V", maincam->by); + snprint(stats[Scambz], sizeof(stats[Scambz]), "bz %V", maincam->bz); + for(i = 0; i < Se; i++) + stringn(maincam->viewport, addpt(screen->r.min, Pt(10, 10 + i*font->height)), display->black, ZP, font, stats[i], sizeof(stats[i])); +} + +void +redraw(void) +{ + Triangle3 tmp; + static TTriangle3 *vistris; + static int nallocvistri; + Triangle trit; + Point3 n; + u8int c; + int i, nvistri; + + nvistri = 0; + if(nallocvistri == 0 && vistris == nil){ + nallocvistri = model.ntri/2; + vistris = emalloc(nallocvistri*sizeof(TTriangle3)); + } + for(i = 0; i < model.ntri; i++){ + /* world to camera */ + tmp.p0 = WORLD2VCS(maincam, model.tris[i].p0); + tmp.p1 = WORLD2VCS(maincam, model.tris[i].p1); + tmp.p2 = WORLD2VCS(maincam, model.tris[i].p2); + /* back-face culling */ + n = normvec3(crossvec3(subpt3(tmp.p1, tmp.p0), subpt3(tmp.p2, tmp.p0))); + if(dotvec3(n, mulpt3(tmp.p0, -1)) <= 0) + continue; + /* camera to projected ndc */ + tmp.p0 = VCS2NDC(maincam, tmp.p0); + tmp.p1 = VCS2NDC(maincam, tmp.p1); + tmp.p2 = VCS2NDC(maincam, tmp.p2); + /* clipping */ + /* + * no clipping for now, the whole triangle is ignored + * if any of its vertices gets outside the fustrum. + */ + if(isclipping(tmp.p0) || isclipping(tmp.p1) || isclipping(tmp.p2)) + continue; + if(nvistri >= nallocvistri){ + nallocvistri += model.ntri/3; + vistris = erealloc(vistris, nallocvistri*sizeof(TTriangle3)); + } + vistris[nvistri] = (TTriangle3)tmp; + c = 0xff*fabs(dotvec3(n, Vec3(0, 0, 1))); + vistris[nvistri].tx = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c<<24|c<<16|c<<8|0xff); + nvistri++; + } + qsort(vistris, nvistri, sizeof(TTriangle3), depthcmp); + lockdisplay(display); + draw(maincam->viewport, maincam->viewport->r, display->white, nil, ZP); + drawaxis(); + for(i = 0; i < nvistri; i++){ + /* ndc to screen */ + trit.p0 = toviewport(maincam, vistris[i].p0); + trit.p1 = toviewport(maincam, vistris[i].p1); + trit.p2 = toviewport(maincam, vistris[i].p2); + filltriangle(maincam->viewport, trit, vistris[i].tx, ZP); + triangle(maincam->viewport, trit, 0, display->black, ZP); + freeimage(vistris[i].tx); + } + drawstats(); + flushimage(display, 1); + unlockdisplay(display); +} + +void +scrsynproc(void *) +{ + threadsetname("scrsynproc"); + for(;;){ + rlock(&worldlock); + redraw(); + runlock(&worldlock); + sleep(FPS2MS(60)); + } +} + +void +screenshot(void) +{ + int fd; + static char buf[128]; + + enter("Path", buf, sizeof buf, mctl, nil, nil); + if(buf[0] == 0) + return; + fd = create(buf, OWRITE, 0644); + if(fd < 0) + sysfatal("open: %r"); + if(writeimage(fd, screen, 1) < 0) + sysfatal("writeimage: %r"); + close(fd); +} + +void +mouse(void) +{ + if(mctl->buttons & 1) + fprint(2, "%v\n", fromviewport(maincam, mctl->xy)); + if(mctl->buttons & 8){ + maincam->fov -= 5; + if(maincam->fov < 1) + maincam->fov = 1; + reloadcamera(maincam); + } + if(mctl->buttons & 16){ + maincam->fov += 5; + if(maincam->fov > 359) + maincam->fov = 359; + reloadcamera(maincam); + } +} + +void +kbdproc(void *) +{ + Rune r, *a; + char buf[128], *s; + int fd, n; + + threadsetname("kbdproc"); + if((fd = open("/dev/kbd", OREAD)) < 0) + sysfatal("kbdproc: %r"); + memset(buf, 0, sizeof buf); + for(;;){ + if(buf[0] != 0){ + n = strlen(buf)+1; + memmove(buf, buf+n, sizeof(buf)-n); + } + if(buf[0] == 0){ + if((n = read(fd, buf, sizeof(buf)-1)) <= 0) + break; + buf[n-1] = 0; + buf[n] = 0; + } + if(buf[0] == 'c'){ + if(utfrune(buf, Kdel)){ + close(fd); + threadexitsall(nil); + } + } + if(buf[0] != 'k' && buf[0] != 'K') + continue; + s = buf+1; + kdown = 0; + while(*s){ + s += chartorune(&r, s); + for(a = keys; a < keys+Ke; a++) + if(r == *a){ + kdown |= 1 << a-keys; + break; + } + } + } +} + +void +handlekeys(void) +{ + if(kdown & 1<p, maincam->bz), maincam->bz, maincam->by); + if(kdown & 1<p, maincam->bz), maincam->bz, maincam->by); + if(kdown & 1<p, maincam->bx), maincam->bz, maincam->by); + if(kdown & 1<p, maincam->bx), maincam->bz, maincam->by); + if(kdown & 1<p, maincam->by), maincam->bz, maincam->by); + if(kdown & 1<p, maincam->by), maincam->bz, maincam->by); + if(kdown & 1<bz, maincam->bx, 5*DEG)); + if(kdown & 1<bz, maincam->bx, -5*DEG)); + if(kdown & 1<bz, maincam->by, 5*DEG)); + if(kdown & 1<bz, maincam->by, -5*DEG)); + if(kdown & 1<p, maincam->bz, qrotate(maincam->by, maincam->bz, 5*DEG)); + if(kdown & 1<p, maincam->bz, qrotate(maincam->by, maincam->bz, -5*DEG)); + if(kdown & 1<viewport = screen; + reloadcamera(maincam); +} + +void +usage(void) +{ + fprint(2, "usage: %s\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + OBJ *objmesh; + + fmtinstall('V', Vfmt); + fmtinstall('v', vfmt); + ARGBEGIN{ + default: usage(); + case 'l': + mdlpath = EARGF(usage()); + break; + }ARGEND; + if(argc != 0) + usage(); + if(initdraw(nil, nil, "3d") < 0) + sysfatal("initdraw: %r"); + if((mctl = initmouse(nil, screen)) == nil) + sysfatal("initmouse: %r"); + placecamera(&cams[0], Pt3(2, 0, -4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0)); + configcamera(&cams[0], screen, 90, 0.1, 100, Ppersp); + placecamera(&cams[1], Pt3(-2, 0, -4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0)); + configcamera(&cams[1], screen, 120, 0.1, 100, Ppersp); + placecamera(&cams[2], Pt3(-2, 0, 4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0)); + configcamera(&cams[2], screen, 90, 0.1, 100, Ppersp); + placecamera(&cams[3], Pt3(2, 0, 4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0)); + configcamera(&cams[3], screen, 120, 0.1, 100, Ppersp); + maincam = &cams[0]; + if((objmesh = objparse(mdlpath)) == nil) + sysfatal("objparse: %r"); + display->locking = 1; + unlockdisplay(display); + proccreate(scrsynproc, nil, mainstacksize); + proccreate(kbdproc, nil, mainstacksize); + t0 = nsec(); + for(;;){ + enum {MOUSE, RESIZE}; + Alt a[] = { + {mctl->c, &mctl->Mouse, CHANRCV}, + {mctl->resizec, nil, CHANRCV}, + {nil, nil, CHANNOBLK} + }; + wlock(&worldlock); + switch(alt(a)){ + case MOUSE: mouse(); break; + case RESIZE: resize(); break; + } + Δt = (nsec()-t0)/1e9; + handlekeys(); + t0 += Δt*1e9; + wunlock(&worldlock); + sleep(16); + } +} -- cgit v1.2.3