aboutsummaryrefslogtreecommitdiff
path: root/vis.c
diff options
context:
space:
mode:
Diffstat (limited to 'vis.c')
-rw-r--r--vis.c336
1 files changed, 211 insertions, 125 deletions
diff --git a/vis.c b/vis.c
index 6f3dbe2..ce45b0c 100644
--- a/vis.c
+++ b/vis.c
@@ -40,6 +40,14 @@ Rune keys[Ke] = {
[Kcam3] = KF|4,
[Khud] = 'h',
};
+char *skyboxpaths[] = {
+ "cubemap/skybox/left.pic",
+ "cubemap/skybox/right.pic",
+ "cubemap/skybox/bottom.pic",
+ "cubemap/skybox/top.pic",
+ "cubemap/skybox/front.pic",
+ "cubemap/skybox/back.pic",
+};
char stats[Se][256];
Image *screenb;
Mousectl *mctl;
@@ -48,9 +56,10 @@ Channel *drawc;
int kdown;
Shadertab *shader;
Model *model;
-Entity *subject;
Scene *scene;
-double θ, ω = 0;
+QLock drawlk;
+Mouse om;
+Quaternion orient = {1,0,0,0};
Camera cams[4], *maincam;
Camcfg camcfgs[4] = {
@@ -77,9 +86,11 @@ Camcfg camcfgs[4] = {
Point3 center = {0,0,0,1};
LightSource light; /* global point light */
+static int showskybox;
static int doprof;
static int inception;
static int showhud;
+static int shownormals;
Color (*tsampler)(Memimage*,Point2);
static int
@@ -94,21 +105,17 @@ max(int a, int b)
return a > b? a: b;
}
-//void
-//drawaxis(void)
-//{
-// Point3 op = Pt3(0,0,0,1),
-// px = Pt3(1,0,0,1),
-// py = Pt3(0,1,0,1),
-// pz = Pt3(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");
-//}
+static Point3
+Vecquat(Quaternion q)
+{
+ return Vec3(q.i, q.j, q.k);
+}
+
+static Point3
+Ptquat(Quaternion q, double w)
+{
+ return Pt3(q.i, q.j, q.k, w);
+}
Point3
gouraudvshader(VSparams *sp)
@@ -118,41 +125,35 @@ gouraudvshader(VSparams *sp)
double Kd; /* diffuse factor */
double spec;
Point3 pos, lightdir, lookdir;
- Material m;
- Color ambient, diffuse, specular;
+ Material *m;
+ Color ambient, diffuse, specular, lightc;
- sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
- sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
- pos = model2world(sp->su->entity, sp->v->p);
- if(sp->v->mtl != nil){
- m = *sp->v->mtl;
-
- ambient = mulpt3(light.c, Ka);
- ambient.r *= m.ambient.r;
- ambient.g *= m.ambient.g;
- ambient.b *= m.ambient.b;
- ambient.a *= m.ambient.a;
-
- lightdir = normvec3(subpt3(light.p, pos));
- Kd = fmax(0, dotvec3(sp->v->n, lightdir));
- diffuse = mulpt3(light.c, Kd);
- diffuse.r *= m.diffuse.r;
- diffuse.g *= m.diffuse.g;
- diffuse.b *= m.diffuse.b;
- diffuse.a *= m.diffuse.a;
-
- lookdir = normvec3(subpt3(maincam->p, pos));
- lightdir = qrotate(lightdir, sp->v->n, PI);
- spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(light.c, spec*Ks);
- specular.r *= m.specular.r;
- specular.g *= m.specular.g;
- specular.b *= m.specular.b;
- specular.a *= m.specular.a;
-
- sp->v->c = addpt3(ambient, addpt3(diffuse, specular));
- }
- return world2clip(maincam, pos);
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = sp->v->p;
+ m = sp->v->mtl;
+
+ lightdir = normvec3(subpt3(light.p, pos));
+ lightc = getlightcolor(&light, lightdir);
+
+ ambient = mulpt3(lightc, Ka);
+ if(m != nil)
+ ambient = modulapt3(ambient, m->ambient);
+
+ Kd = fmax(0, dotvec3(sp->v->n, lightdir));
+ diffuse = mulpt3(lightc, Kd);
+ if(m != nil)
+ diffuse = modulapt3(diffuse, m->diffuse);
+
+ lookdir = normvec3(subpt3(sp->su->camera->p, pos));
+ lightdir = qrotate(lightdir, sp->v->n, PI);
+ spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m? m->shininess: 1);
+ specular = mulpt3(lightc, spec*Ks);
+ if(m != nil)
+ specular = modulapt3(specular, m->specular);
+
+ sp->v->c = addpt3(ambient, addpt3(diffuse, specular));
+ return world2clip(sp->su->camera, pos);
}
Color
@@ -167,10 +168,8 @@ gouraudshader(FSparams *sp)
else
tc = Pt3(1,1,1,1);
+ c = modulapt3(sp->v.c, tc);
c.a = 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;
}
@@ -182,10 +181,14 @@ phongvshader(VSparams *sp)
Color a, d, s;
double ss;
- sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
- sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
- pos = model2world(sp->su->entity, sp->v->p);
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = sp->v->p;
addvattr(sp->v, "pos", VAPoint, &pos);
+ if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){
+ sp->v->tangent = model2world(sp->su->entity, sp->v->tangent);
+ addvattr(sp->v, "tangent", VAPoint, &sp->v->tangent);
+ }
if(sp->v->mtl != nil){
a = sp->v->mtl->ambient;
d = sp->v->mtl->diffuse;
@@ -196,7 +199,7 @@ phongvshader(VSparams *sp)
addvattr(sp->v, "specular", VAPoint, &s);
addvattr(sp->v, "shininess", VANumber, &ss);
}
- return world2clip(maincam, pos);
+ return world2clip(sp->su->camera, pos);
}
Color
@@ -206,9 +209,10 @@ phongshader(FSparams *sp)
static double Ks = 0.5; /* specular factor */
double Kd; /* diffuse factor */
double spec;
- Color ambient, diffuse, specular, tc, c;
- Point3 pos, lookdir, lightdir;
+ Color ambient, diffuse, specular, tc, c, lightc;
+ Point3 pos, n, lightdir, lookdir;
Material m;
+ RFrame3 TBN;
Vertexattr *va;
va = getvattr(&sp->v, "pos");
@@ -223,28 +227,38 @@ phongshader(FSparams *sp)
va = getvattr(&sp->v, "shininess");
m.shininess = va != nil? va->n: 1;
- ambient = mulpt3(light.c, Ka);
- ambient.r *= m.ambient.r;
- ambient.g *= m.ambient.g;
- ambient.b *= m.ambient.b;
- ambient.a *= m.ambient.a;
-
lightdir = normvec3(subpt3(light.p, pos));
- Kd = fmax(0, dotvec3(sp->v.n, lightdir));
- diffuse = mulpt3(light.c, Kd);
- diffuse.r *= m.diffuse.r;
- diffuse.g *= m.diffuse.g;
- diffuse.b *= m.diffuse.b;
- diffuse.a *= m.diffuse.a;
-
- lookdir = normvec3(subpt3(maincam->p, pos));
- lightdir = qrotate(lightdir, sp->v.n, PI);
+ lightc = getlightcolor(&light, lightdir);
+
+ ambient = mulpt3(lightc, Ka);
+ ambient = modulapt3(ambient, m.ambient);
+
+ /* normal mapping */
+ va = getvattr(&sp->v, "tangent");
+ if(va == nil)
+ n = sp->v.n;
+ else{
+ /* TODO implement this on the VS instead and apply Gram-Schmidt here */
+ n = texture(sp->v.mtl->normalmap, sp->v.uv, neartexsampler);
+ n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
+
+ TBN.p = Pt3(0,0,0,1);
+ TBN.bx = va->p; /* T */
+ TBN.bz = sp->v.n; /* N */
+ TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
+
+ n = normvec3(invrframexform3(n, TBN));
+ }
+
+ Kd = fmax(0, dotvec3(n, lightdir));
+ diffuse = mulpt3(lightc, Kd);
+ diffuse = modulapt3(diffuse, m.diffuse);
+
+ lookdir = normvec3(subpt3(sp->su->camera->p, pos));
+ lightdir = qrotate(lightdir, n, PI);
spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(light.c, spec*Ks);
- specular.r *= m.specular.r;
- specular.g *= m.specular.g;
- specular.b *= m.specular.b;
- specular.a *= m.specular.a;
+ specular = mulpt3(lightc, spec*Ks);
+ specular = modulapt3(specular, m.specular);
if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0)
tc = texture(sp->v.mtl->diffusemap, sp->v.uv, tsampler);
@@ -254,10 +268,8 @@ phongshader(FSparams *sp)
tc = Pt3(1,1,1,1);
c = addpt3(ambient, addpt3(diffuse, specular));
+ c = modulapt3(c, tc);
c.a = 1;
- c.b = fclamp(c.b*tc.b, 0, 1);
- c.g = fclamp(c.g*tc.g, 0, 1);
- c.r = fclamp(c.r*tc.r, 0, 1);
return c;
}
@@ -268,13 +280,15 @@ identvshader(VSparams *sp)
Point3 pos, lightdir;
double intens;
- pos = model2world(sp->su->entity, sp->v->p);
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = 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 = sp->v->mtl->diffuse;
- return world2clip(maincam, pos);
+ return world2clip(sp->su->camera, pos);
}
Color
@@ -302,10 +316,8 @@ identshader(FSparams *sp)
else
tc = Pt3(1,1,1,1);
+ c = modulapt3(sp->v.c, tc);
c.a = 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;
}
@@ -313,7 +325,9 @@ identshader(FSparams *sp)
Point3
ivshader(VSparams *sp)
{
- return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ return world2clip(sp->su->camera, sp->v->p);
}
Color
@@ -428,14 +442,14 @@ getshader(char *name)
void
zoomin(void)
{
- maincam->fov = fclamp(maincam->fov - 1*DEG, 1*DEG, 359*DEG);
+ maincam->fov = fclamp(maincam->fov - 1*DEG, 1*DEG, 180*DEG);
reloadcamera(maincam);
}
void
zoomout(void)
{
- maincam->fov = fclamp(maincam->fov + 1*DEG, 1*DEG, 359*DEG);
+ maincam->fov = fclamp(maincam->fov + 1*DEG, 1*DEG, 180*DEG);
reloadcamera(maincam);
}
@@ -452,6 +466,7 @@ drawstats(void)
snprint(stats[Scambz], sizeof(stats[Scambz]), "bz %V", maincam->bz);
snprint(stats[Sfps], sizeof(stats[Sfps]), "FPS %.0f/%.0f/%.0f/%.0f", !maincam->stats.max? 0: 1e9/maincam->stats.max, !maincam->stats.avg? 0: 1e9/maincam->stats.avg, !maincam->stats.min? 0: 1e9/maincam->stats.min, !maincam->stats.v? 0: 1e9/maincam->stats.v);
snprint(stats[Sframes], sizeof(stats[Sframes]), "frame %llud", maincam->stats.nframes);
+ snprint(stats[Sorient], sizeof(stats[Sorient]), "ℍ %V", (Point3)orient);
for(i = 0; i < Se; i++)
stringbg(screen, addpt(screen->r.min, Pt(10,10 + i*font->height)), display->black, ZP, font, stats[i], display->white, ZP);
}
@@ -465,10 +480,12 @@ redraw(void)
bg = eallocimage(display, UR, RGB24, 1, 0x888888FF);
lockdisplay(display);
- maincam->vp->draw(maincam->vp, screenb);
+ if(shownormals)
+ maincam->vp->fbctl->drawnormals(maincam->vp->fbctl, screenb);
+ else
+ maincam->vp->draw(maincam->vp, screenb);
draw(screen, screen->r, bg, nil, ZP);
draw(screen, screen->r, screenb, nil, ZP);
-// drawaxis();
if(showhud)
drawstats();
flushimage(display, 1);
@@ -476,12 +493,12 @@ redraw(void)
}
void
-drawproc(void *)
+renderproc(void *)
{
uvlong t0, Δt;
int fd;
- threadsetname("drawproc");
+ threadsetname("renderproc");
fd = -1;
if(inception){
@@ -496,6 +513,12 @@ drawproc(void *)
t0 = nsec();
for(;;){
shootcamera(maincam, shader);
+ if(doprof)
+ fprint(2, "R %llud %llud\nE %llud %llud\nT %llud %llud\nr %llud %llud\n\n",
+ maincam->times.R[maincam->times.cur-1].t0, maincam->times.R[maincam->times.cur-1].t1,
+ maincam->times.E[maincam->times.cur-1].t0, maincam->times.E[maincam->times.cur-1].t1,
+ maincam->times.Tn[maincam->times.cur-1].t0, maincam->times.Tn[maincam->times.cur-1].t1,
+ maincam->times.Rn[maincam->times.cur-1].t0, maincam->times.Rn[maincam->times.cur-1].t1);
Δt = nsec() - t0;
if(Δt > HZ2MS(60)*1000000ULL){
nbsend(drawc, nil);
@@ -506,37 +529,97 @@ drawproc(void *)
if((model->tex = readmemimage(fd)) == nil)
sysfatal("readmemimage: %r");
}
- light.p = qrotate(light.p, Vec3(0,1,0), θ+fmod(ω*Δt/1e9, 2*PI));
}
}
}
void
+drawproc(void *)
+{
+ threadsetname("drawproc");
+
+ for(;;)
+ if(recv(drawc, nil) && canqlock(&drawlk)){
+ redraw();
+ qunlock(&drawlk);
+ }
+}
+
+static Color
+ul2col(ulong l)
+{
+ Color c;
+
+ c.a = (l & 0xff)/255.0;
+ c.b = (l>>8 & 0xff)/255.0;
+ c.g = (l>>16 & 0xff)/255.0;
+ c.r = (l>>24 & 0xff)/255.0;
+ return c;
+}
+
+void
+lmb(void)
+{
+ Entity *e;
+ Quaternion Δorient;
+
+ if((om.buttons^mctl->buttons) == 0){
+ Δorient = orient;
+ qball(screen->r, om.xy, mctl->xy, &orient, nil);
+ Δorient = mulq(orient, invq(Δorient));
+
+ for(e = scene->ents.next; e != &scene->ents; e = e->next){
+ e->bx = vcs2world(maincam, Vecquat(mulq(mulq(Δorient, Quatvec(0, world2vcs(maincam, e->bx))), invq(Δorient))));
+ e->by = vcs2world(maincam, Vecquat(mulq(mulq(Δorient, Quatvec(0, world2vcs(maincam, e->by))), invq(Δorient))));
+ e->bz = vcs2world(maincam, Vecquat(mulq(mulq(Δorient, Quatvec(0, world2vcs(maincam, e->bz))), invq(Δorient))));
+ }
+ }else{
+ Framebuf *fb;
+ Point p;
+ Color c, n;
+ double z;
+
+ p = subpt(mctl->xy, screen->r.min);
+ qlock(maincam->vp->fbctl);
+ fb = maincam->vp->getfb(maincam->vp);
+ c = ul2col(fb->cb[p.y*Dx(fb->r) + p.x]);
+ n = ul2col(fb->nb[p.y*Dx(fb->r) + p.x]);
+ z = fb->zb[p.y*Dx(fb->r) + p.x];
+ qunlock(maincam->vp->fbctl);
+ snprint(stats[Spixcol], sizeof(stats[Spixcol]), "c %V z %g", c, z);
+ snprint(stats[Snorcol], sizeof(stats[Snorcol]), "n %V", n);
+ }
+}
+
+void
mmb(void)
{
enum {
MOVELIGHT,
TSNEAREST,
TSBILINEAR,
+ SHOWNORMALS,
};
static char *items[] = {
[MOVELIGHT] "move light",
[TSNEAREST] "use nearest sampler",
[TSBILINEAR] "use bilinear sampler",
+ [SHOWNORMALS] "show normals",
nil,
};
static Menu menu = { .item = items };
char buf[256], *f[3];
int nf;
+ qlock(&drawlk);
switch(menuhit(2, mctl, &menu, _screen)){
case MOVELIGHT:
snprint(buf, sizeof buf, "%g %g %g", light.p.x, light.p.y, light.p.z);
if(enter("light pos", buf, sizeof buf, mctl, kctl, nil) <= 0)
- return;
+ break;
nf = tokenize(buf, f, 3);
if(nf != 3)
- return;
+ break;
light.p.x = strtod(f[0], nil);
light.p.y = strtod(f[1], nil);
light.p.z = strtod(f[2], nil);
@@ -547,7 +630,11 @@ mmb(void)
case TSBILINEAR:
tsampler = bilitexsampler;
break;
+ case SHOWNORMALS:
+ shownormals ^= 1;
+ break;
}
+ qunlock(&drawlk);
nbsend(drawc, nil);
}
@@ -565,18 +652,22 @@ rmb(void)
static Menu menu = { .gen = genrmbmenuitem };
int idx;
+ qlock(&drawlk);
idx = menuhit(3, mctl, &menu, _screen);
- if(idx < 0)
- return;
- shader = &shadertab[idx];
- for(idx = 0; idx < nelem(cams); idx++)
- memset(&cams[idx].stats, 0, sizeof(cams[idx].stats));
+ if(idx >= 0){
+ shader = &shadertab[idx];
+ for(idx = 0; idx < nelem(cams); idx++)
+ memset(&cams[idx].stats, 0, sizeof(cams[idx].stats));
+ }
+ qunlock(&drawlk);
nbsend(drawc, nil);
}
void
mouse(void)
{
+ if((mctl->buttons & 1) != 0)
+ lmb();
if((mctl->buttons & 2) != 0)
mmb();
if((mctl->buttons & 4) != 0)
@@ -585,6 +676,7 @@ mouse(void)
zoomin();
if((mctl->buttons & 16) != 0)
zoomout();
+ om = mctl->Mouse;
}
void
@@ -726,7 +818,7 @@ confproc(void)
void
usage(void)
{
- fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] [-ω yrot] model...\n", argv0);
+ fprint(2, "usage: %s [-s] [-t texture] model...\n", argv0);
exits("usage");
}
@@ -736,19 +828,16 @@ threadmain(int argc, char *argv[])
Viewport *v;
Renderer *rctl;
Channel *keyc;
+ Entity *subject;
OBJ *obj;
- char *texpath, *norpath, *sname, *mdlpath;
+ char *texpath, *mdlpath;
int i, fd;
GEOMfmtinstall();
texpath = nil;
- norpath = nil;
- sname = "gouraud";
ARGBEGIN{
+ case 's': showskybox++; break;
case 't': texpath = EARGF(usage()); break;
- case 'n': norpath = EARGF(usage()); break;
- case 's': sname = EARGF(usage()); break;
- case L'ω': ω = strtod(EARGF(usage()), nil)*DEG; break;
case L'ι': inception++; break;
case 'p': doprof++; break;
default: usage();
@@ -758,15 +847,15 @@ threadmain(int argc, char *argv[])
confproc();
- if((shader = getshader(sname)) == nil)
- sysfatal("couldn't find %s shader", sname);
+ if((shader = getshader("gouraud")) == nil)
+ sysfatal("couldn't find gouraud shader");
scene = newscene(nil);
while(argc--){
mdlpath = argv[argc];
model = newmodel();
subject = newentity(model);
- subject->p.x = argc*4;
+// subject->p.x = argc*4;
scene->addent(scene, subject);
if((obj = objparse(mdlpath)) == nil)
@@ -782,15 +871,9 @@ threadmain(int argc, char *argv[])
sysfatal("readmemimage: %r");
close(fd);
}
- if(argc == 0 && norpath != nil){
- fd = open(norpath, OREAD);
- if(fd < 0)
- sysfatal("open: %r");
- if((model->nor = readmemimage(fd)) == nil)
- sysfatal("readmemimage: %r");
- close(fd);
- }
}
+ if(showskybox)
+ scene->skybox = readcubemap(skyboxpaths);
if(memimageinit() != 0)
sysfatal("memimageinit: %r");
@@ -806,13 +889,17 @@ threadmain(int argc, char *argv[])
v = mkviewport(screenb->r);
placecamera(&cams[i], camcfgs[i].p, camcfgs[i].lookat, camcfgs[i].up);
configcamera(&cams[i], v, camcfgs[i].fov, camcfgs[i].clipn, camcfgs[i].clipf, camcfgs[i].ptype);
- cams[i].s = scene;
+ cams[i].scene = scene;
cams[i].rctl = rctl;
}
maincam = &cams[3];
light.p = Pt3(0,100,100,1);
+// light.dir = Vec3(0,-1,0);
light.c = Pt3(1,1,1,1);
light.type = LIGHT_POINT;
+// light.type = LIGHT_SPOT;
+// light.θu = 30*DEG;
+// light.θp = 5*DEG;
tsampler = neartexsampler;
kctl = emalloc(sizeof *kctl);
@@ -824,22 +911,21 @@ threadmain(int argc, char *argv[])
proccreate(kbdproc, nil, mainstacksize);
proccreate(keyproc, keyc, mainstacksize);
+ proccreate(renderproc, nil, mainstacksize);
proccreate(drawproc, nil, mainstacksize);
for(;;){
- enum {MOUSE, RESIZE, KEY, DRAW};
+ enum {MOUSE, RESIZE, KEY};
Alt a[] = {
{mctl->c, &mctl->Mouse, CHANRCV},
{mctl->resizec, nil, CHANRCV},
{keyc, nil, CHANRCV},
- {drawc, nil, CHANRCV},
{nil, nil, CHANEND}
};
switch(alt(a)){
case MOUSE: mouse(); break;
case RESIZE: resize(); break;
case KEY: handlekeys(); break;
- case DRAW: redraw(); break;
}
}
}