aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2023-01-29 22:27:33 +0000
committerrodri <rgl@antares-labs.eu>2023-01-29 22:27:33 +0000
commite70ecd9d84578dad435a39b40592f9a7cd1908d3 (patch)
tree0abadddf4f131a1aa30fed5a3a434805868fa1e6 /main.c
downloadqball-e70ecd9d84578dad435a39b40592f9a7cd1908d3.tar.gz
qball-e70ecd9d84578dad435a39b40592f9a7cd1908d3.tar.bz2
qball-e70ecd9d84578dad435a39b40592f9a7cd1908d3.zip
initial public release.
the original qball doesn't seem to work at all. burnzez's qb adaptation has proven to be very close, with some minor modifications, but still doesn't get it.
Diffstat (limited to 'main.c')
-rw-r--r--main.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..57e5c71
--- /dev/null
+++ b/main.c
@@ -0,0 +1,382 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include "dat.h"
+#include "fns.h"
+
+Mousectl *mctl;
+Keyboardctl *kctl;
+Mouse om;
+Point orig;
+Vector basis;
+double Znear, Zfar, Zoff, a;
+Matrix proj;
+Vector3 light;
+double θ, ω;
+double t0, Δt;
+int dowireframe;
+RWLock worldlock;
+Quaternion orient;
+
+Mesh model;
+/*Triangle3 cube[] = {
+ 0,0,0, 0,1,0, 1,1,0,
+ 0,0,0, 1,1,0, 1,0,0,
+
+ 1,0,0, 1,1,0, 1,1,1,
+ 1,0,0, 1,1,1, 1,0,1,
+
+ 1,0,1, 1,1,1, 0,1,1,
+ 1,0,1, 0,1,1, 0,0,1,
+
+ 0,0,1, 0,1,1, 0,1,0,
+ 0,0,1, 0,1,0, 0,0,0,
+
+ 0,1,0, 0,1,1, 1,1,1,
+ 0,1,0, 1,1,1, 1,1,0,
+
+ 1,0,1, 0,0,1, 0,0,0,
+ 1,0,1, 0,0,0, 1,0,0,
+};*/
+
+void *
+emalloc(ulong n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("malloc: %r");
+ memset(p, 0, n);
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+void *
+erealloc(void *ptr, ulong n)
+{
+ void *p;
+
+ p = realloc(ptr, n);
+ if(p == nil)
+ sysfatal("realloc: %r");
+ setrealloctag(p, getcallerpc(&ptr));
+ return p;
+}
+
+Image *
+eallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col)
+{
+ Image *i;
+
+ i = allocimage(d, r, chan, repl, col);
+ if(i == nil)
+ sysfatal("allocimage: %r");
+ return i;
+}
+
+#pragma varargck type "V" Vector3
+int
+Vfmt(Fmt *f)
+{
+ Vector3 v;
+
+ v = va_arg(f->args, Vector3);
+ return fmtprint(f, "(%g %g %g)", v.x, v.y, v.z);
+}
+
+#pragma varargck type "H" Quaternion
+int
+Hfmt(Fmt *f)
+{
+ Quaternion q;
+
+ q = va_arg(f->args, Quaternion);
+ return fmtprint(f, "(%g %g %g %g)", q.r, q.i, q.j, q.k);
+}
+
+#pragma varargck type "T" Triangle3
+int
+Tfmt(Fmt *f)
+{
+ Triangle3 t;
+
+ t = va_arg(f->args, Triangle3);
+ return fmtprint(f, "%V%V%V", t.p0, t.p1, t.p2);
+}
+
+Point
+vectopt(Vector v)
+{
+ return Pt(v.x, v.y);
+}
+
+Point
+toscreen(Vector p)
+{
+ return addpt(orig, Pt(p.x*basis.x, p.y*basis.y));
+}
+
+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 za > zb ? -1 : 1;
+}
+
+void
+drawinfo(void)
+{
+ char buf[128];
+
+ snprint(buf, sizeof buf, "%H", orient);
+ string(screen, addpt(screen->r.min, Pt(30,30)), display->white, ZP, font, buf);
+}
+
+void
+redraw(void)
+{
+ Triangle3 trans, *vistris;
+ Vector3 n;
+// Quaternion Xaxis, Yaxis, Zaxis;
+// Quaternion q;
+ Matrix T = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, Zoff,
+ 0, 0, 0, 1,
+ }, S = {
+ Dx(screen->r)/2, 0, 0, 0,
+ 0, Dy(screen->r)/2, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+ u32int c;
+ int nvistri, i;
+
+ vistris = nil;
+ nvistri = 0;
+// Xaxis = Quat(cos(θ/4), sin(θ/4), 0, 0);
+// Yaxis = Quat(cos(θ/6), 0, sin(θ/6), 0);
+// Zaxis = Quat(cos(θ/2), 0, 0, sin(θ/2));
+// q = mulq(Zaxis, mulq(Yaxis, Xaxis));
+ lockdisplay(display);
+ draw(screen, screen->r, display->black, nil, ZP);
+ for(i = 0; i < model.ntri; i++){
+// trans.p0 = Vecquat(mulq(mulq(q, Quatvec(0, model.tris[i].p0)), invq(q)));
+// trans.p1 = Vecquat(mulq(mulq(q, Quatvec(0, model.tris[i].p1)), invq(q)));
+// trans.p2 = Vecquat(mulq(mulq(q, Quatvec(0, model.tris[i].p2)), invq(q)));
+
+// trans.p0 = Vecquat(mulq(mulq(invq(orient), Quatvec(0, model.tris[i].p0)), orient));
+// trans.p1 = Vecquat(mulq(mulq(invq(orient), Quatvec(0, model.tris[i].p1)), orient));
+// trans.p2 = Vecquat(mulq(mulq(invq(orient), Quatvec(0, model.tris[i].p2)), orient));
+
+ trans.p0 = Vecquat(mulq(mulq(orient, Quatvec(0, model.tris[i].p0)), invq(orient)));
+ trans.p1 = Vecquat(mulq(mulq(orient, Quatvec(0, model.tris[i].p1)), invq(orient)));
+ trans.p2 = Vecquat(mulq(mulq(orient, Quatvec(0, model.tris[i].p2)), invq(orient)));
+
+ trans.p0 = mulvecm(trans.p0, T);
+ trans.p1 = mulvecm(trans.p1, T);
+ trans.p2 = mulvecm(trans.p2, T);
+
+ n = normvec3(crossvec(
+ subvec3(trans.p1, trans.p0),
+ subvec3(trans.p2, trans.p0)));
+ if(dotvec3(n, subvec3(trans.p0, Vec3(0, 0, 0))) < 0){
+ trans.p0 = mulvecm(trans.p0, proj);
+ trans.p1 = mulvecm(trans.p1, proj);
+ trans.p2 = mulvecm(trans.p2, proj);
+ trans.p0 = addvec3(trans.p0, Vec3(1, 1, 0));
+ trans.p1 = addvec3(trans.p1, Vec3(1, 1, 0));
+ trans.p2 = addvec3(trans.p2, Vec3(1, 1, 0));
+ trans.p0 = mulvecm(trans.p0, S);
+ trans.p1 = mulvecm(trans.p1, S);
+ trans.p2 = mulvecm(trans.p2, S);
+ c = 0xff*fabs(dotvec3(n, light));
+ trans.tx = eallocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c<<24|c<<16|c<<8|0xff);
+ vistris = erealloc(vistris, ++nvistri*sizeof(Triangle3));
+ vistris[nvistri-1] = trans;
+ }
+ }
+ qsort(vistris, nvistri, sizeof(Triangle3), depthcmp);
+ for(i = 0; i < nvistri; i++){
+ filltriangle(screen, Trianpt(
+ toscreen(Vec(vistris[i].p0.x, vistris[i].p0.y)),
+ toscreen(Vec(vistris[i].p1.x, vistris[i].p1.y)),
+ toscreen(Vec(vistris[i].p2.x, vistris[i].p2.y))
+ ), vistris[i].tx, ZP);
+ if(dowireframe)
+ triangle(screen, Trianpt(
+ toscreen(Vec(vistris[i].p0.x, vistris[i].p0.y)),
+ toscreen(Vec(vistris[i].p1.x, vistris[i].p1.y)),
+ toscreen(Vec(vistris[i].p2.x, vistris[i].p2.y))
+ ), 0, display->black, ZP);
+ freeimage(vistris[i].tx);
+ }
+ free(vistris);
+ drawinfo();
+ flushimage(display, 1);
+ unlockdisplay(display);
+}
+
+void
+lmb(void)
+{
+// double tmp;
+
+// qball(screen->r, mctl->xy, &orient, nil);
+ if(om.buttons & 1)
+ qb(screen->r, om.xy, mctl->xy, &orient, nil);
+// fprint(2, "orient %H\n", orient);
+}
+
+void
+rmb(void)
+{
+ enum {
+ DOWIREFRM,
+ };
+ static char *items[] = {
+ [DOWIREFRM] "toggle wireframe",
+ nil,
+ };
+ static Menu menu = { .item = items };
+
+ switch(menuhit(3, mctl, &menu, nil)){
+ case DOWIREFRM:
+ dowireframe ^= 1;
+ break;
+ }
+ t0 = nsec();
+}
+
+void
+mouse(void)
+{
+ if(mctl->buttons & 1)
+ lmb();
+ if(mctl->buttons & 4)
+ rmb();
+ if(mctl->buttons & 8)
+ Zoff -= 0.2;
+ if(mctl->buttons & 16)
+ Zoff += 0.2;
+ om = mctl->Mouse;
+}
+
+void
+key(Rune r)
+{
+ switch(r){
+ case Kdel:
+ case 'q':
+ threadexitsall(nil);
+ case Kpgup:
+ Zoff += 0.2;
+ break;
+ case Kpgdown:
+ Zoff -= 0.2;
+ break;
+ }
+}
+
+void
+resized(void)
+{
+ lockdisplay(display);
+ if(getwindow(display, Refnone) < 0)
+ fprint(2, "can't reattach to window\n");
+ unlockdisplay(display);
+ orig = Pt(screen->r.min.x, screen->r.max.y);
+ a = (double)Dy(screen->r)/Dx(screen->r);
+ proj[0][0] = a*(1/tan(FOV/2*DEG));
+ redraw();
+}
+
+void
+scrsynproc(void *)
+{
+ threadsetname("scrsynproc");
+ for(;;){
+ rlock(&worldlock);
+ redraw();
+ runlock(&worldlock);
+ sleep(SEC/FPS);
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ Rune r;
+
+ fmtinstall('V', Vfmt);
+ fmtinstall('H', Hfmt);
+ fmtinstall('T', Tfmt);
+ ARGBEGIN{
+ default: usage();
+ }ARGEND;
+
+ if(initdraw(nil, nil, "threedee") < 0)
+ sysfatal("initdraw: %r");
+ if((mctl = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse: %r");
+ if((kctl = initkeyboard(nil)) == nil)
+ sysfatal("initkeyboard: %r");
+ orig = Pt(screen->r.min.x, screen->r.max.y);
+ basis = Vec(1, -1);
+ orient = Quat(1, 1, 0, 0);
+ Znear = 0.1;
+ Zfar = 1000;
+ Zoff = 2;
+ a = (double)Dy(screen->r)/Dx(screen->r);
+ proj[0][0] = a*(1/tan(FOV/2*DEG));
+ proj[1][1] = 1/tan(FOV/2*DEG);
+ proj[2][2] = Zfar / (Zfar + Znear);
+ proj[2][3] = -Zfar * Znear / (Zfar + Znear);
+ proj[3][2] = 1;
+ light = Vec3(0, 0, -1);
+ if((model.ntri = objread("mdl/rocket.obj", &model.tris)) < 0)
+ sysfatal("objread: %r");
+ display->locking = 1;
+ unlockdisplay(display);
+ proccreate(scrsynproc, nil, STACK);
+ ω = 1;
+ t0 = nsec();
+ for(;;){
+ enum {MOUSE, RESIZE, KBD};
+ Alt a[] = {
+ {mctl->c, &mctl->Mouse, CHANRCV},
+ {mctl->resizec, nil, CHANRCV},
+ {kctl->c, &r, CHANRCV},
+ {nil, nil, CHANNOBLK}
+ };
+ wlock(&worldlock);
+ switch(alt(a)){
+ case MOUSE: mouse(); break;
+ case RESIZE: resized(); break;
+ case KBD: key(r); break;
+ }
+ Δt = (nsec()-t0)/1e9;
+ θ += ω*Δt;
+ t0 += Δt*1e9;
+ wunlock(&worldlock);
+ sleep(SEC/FPS);
+ }
+}