shithub: 3dee

Download patch

ref: 702e1d92ff4e270f5be88d1b5b190c4de758a101
parent: 53c0208f4caf8701189484e6125821f69e249f94
author: rodri <rgl@antares-labs.eu>
date: Tue May 14 12:40:49 EDT 2024

use real lengths in solar. bring a qball for vis.

--- a/fns.h
+++ b/fns.h
@@ -2,3 +2,4 @@
 void *erealloc(void*, ulong);
 Image *eallocimage(Display*, Rectangle, ulong, int, ulong);
 Memimage *eallocmemimage(Rectangle, ulong);
+void qb(Rectangle, Point, Point, Quaternion*, Quaternion*);
--- a/mdl/planet.mtl
+++ b/mdl/planet.mtl
@@ -1,6 +1,5 @@
 newmtl Sol
 Kd 1.0 1.0 1.0
-map_Kd sol_diffuse.jpg
 
 newmtl Mercury
 Kd 1.0 1.0 1.0
binary files a/mdl/sol_diffuse.jpg /dev/null differ
--- a/mkfile
+++ b/mkfile
@@ -7,6 +7,7 @@
 
 OFILES=\
 	alloc.$O\
+	qb.$O\
 
 HFILES=dat.h fns.h
 
--- /dev/null
+++ b/qb.c
@@ -1,0 +1,86 @@
+/*
+ * Ken Shoemake's Quaternion rotation controller
+ * “Arcball Rotation Control”, Graphics Gems IV § III.1, pp. 175-192, August 1994.
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "libobj/obj.h"
+#include "libgraphics/graphics.h"
+#include "fns.h"
+
+static int
+min(int a, int b)
+{
+	return a < b? a: b;
+}
+
+/*
+ * Convert a mouse point into a unit quaternion, flattening if
+ * constrained to a particular plane.
+ */
+static Quaternion
+mouseq(Point2 p, Quaternion *axis)
+{
+	double l;
+	Quaternion q;
+	double rsq = p.x*p.x + p.y*p.y;	/* quadrance */
+
+	if(rsq > 1){	/* outside the sphere */
+		rsq = sqrt(rsq);
+		q.r = 0;
+		q.i = p.x/rsq;
+		q.j = p.y/rsq;
+		q.k = 0;
+	}else{		/* within the sphere */
+		q.r = 0;
+		q.i = p.x;
+		q.j = p.y;
+		q.k = sqrt(1 - rsq);
+	}
+
+	if(axis != nil){
+		l    = dotq(q, *axis);
+		q.i -= l*axis->i;
+		q.j -= l*axis->j;
+		q.k -= l*axis->k;
+		l    = qlen(q);
+		if(l != 0){
+			q.i /= l;
+			q.j /= l;
+			q.k /= l;
+		}
+	}
+
+	return q;
+}
+
+void
+qb(Rectangle r, Point p0, Point p1, Quaternion *orient, Quaternion *axis)
+{
+	Quaternion q, down;
+	Point2 rmin, rmax;
+	Point2 s0, s1;	/* screen coords */
+	Point2 v0, v1;	/* unit sphere coords */
+	Point2 ctlcen;	/* controller center */
+	double ctlrad;	/* controller radius */
+
+	rmin = Vec2(r.min.x, r.min.y);
+	rmax = Vec2(r.max.x, r.max.y);
+	s0 = Vec2(p0.x, p0.y);
+	s1 = Vec2(p1.x, p1.y);
+	ctlcen = divpt2(addpt2(rmin, rmax), 2);
+	ctlrad = min(Dx(r), Dy(r));
+	v0 = divpt2(subpt2(s0, ctlcen), ctlrad);
+	down = invq(mouseq(v0, axis));
+
+	q = *orient;
+	v1 = divpt2(subpt2(s1, ctlcen), ctlrad);
+	*orient = mulq(q, mulq(down, mouseq(v1, axis)));
+}
--- a/solar.c
+++ b/solar.c
@@ -109,17 +109,17 @@
  [Khud]		= 'h',
 };
 Planet planets[] = {
-	{ .id = 10,	.name = "Sol",		.scale = 100 },
-	{ .id = 1,	.name = "Mercury",	.scale = 0.333333 },
-	{ .id = 2,	.name = "Venus",	.scale = 0.8 },
-	{ .id = 399,	.name = "Earth",	.scale = 1 },
-	{ .id = 301,	.name = "Luna",		.scale = 0.25 },
-	{ .id = 4,	.name = "Mars",		.scale = 0.5 },
-	{ .id = 5,	.name = "Jupiter",	.scale = 11 },
-	{ .id = 6,	.name = "Saturn",	.scale = 9 },
-	{ .id = 7,	.name = "Uranus",	.scale = 4 },
-	{ .id = 8,	.name = "Neptune",	.scale = 3.666666 },
-	{ .id = 9,	.name = "Pluto",	.scale = 0.166666 },
+	{ .id = 10,	.name = "Sol",		.scale = 695700 },
+	{ .id = 1,	.name = "Mercury",	.scale = 2439.4 },
+	{ .id = 2,	.name = "Venus",	.scale = 6051.8 },
+	{ .id = 399,	.name = "Earth",	.scale = 6371.0084 },
+	{ .id = 301,	.name = "Luna",		.scale = 1737.4 },
+	{ .id = 4,	.name = "Mars",		.scale = 3389.50 },
+	{ .id = 5,	.name = "Jupiter",	.scale = 69911 },
+	{ .id = 6,	.name = "Saturn",	.scale = 58232 },
+	{ .id = 7,	.name = "Uranus",	.scale = 25362 },
+	{ .id = 8,	.name = "Neptune",	.scale = 24622 },
+	{ .id = 9,	.name = "Pluto",	.scale = 1188.3 },
 };
 char stats[Se][256];
 char datefmt[] = "YYYY-MM-DD";
@@ -129,12 +129,12 @@
 Mousectl *mctl;
 Keyboardctl *kctl;
 Channel *drawc;
+Mouse om;
 int kdown;
 Tm date;
 char datestr[16];
 Model *model;
 Scene *scene;
-double θ, ω = 0;
 
 Camera camera;
 Camcfg cameracfg = {
@@ -144,7 +144,9 @@
 	80*DEG, 0.01, 1e12, PERSPECTIVE
 };
 Point3 center = {0,0,0,1};
+double speed = 10;
 
+static int museummode;
 static int doprof;
 static int showhud;
 
@@ -242,7 +244,6 @@
 		p = strchr(p, '=');
 		planets[i].body->p.z = strtod(++p, nil);
 		planets[i].body->p.w = 1;
-		planets[i].body->p = divpt3(planets[i].body->p, 1e5);
 		free(s);
 		fprint(2, "%s ready\n", planets[i].name);
 	}
@@ -288,15 +289,13 @@
 
 	if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0)
 		tc = texture(sp->v.mtl->diffusemap, sp->v.uv, neartexsampler);
-	else if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0)
-		tc = texture(sp->su->entity->mdl->tex, sp->v.uv, neartexsampler);
 	else
 		tc = Pt3(1,1,1,1);
 
 	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);
+	c.b = fclamp(tc.b, 0, 1);
+	c.g = fclamp(tc.g, 0, 1);
+	c.r = fclamp(tc.r, 0, 1);
 
 	return c;
 }
@@ -411,7 +410,7 @@
 	if(idx < 0)
 		return;
 	p = &planets[idx];
-	placecamera(&camera, addpt3(p->body->p, Vec3(0,0,10)), p->body->p, cameracfg.up);
+	placecamera(&camera, addpt3(p->body->p, Vec3(0,0,1.5*p->scale)), p->body->p, cameracfg.up);
 	nbsend(drawc, nil);
 }
 
@@ -421,6 +420,9 @@
 	Tm t;
 	char buf[16];
 
+	if(museummode)
+		return;
+
 	memmove(buf, datestr, sizeof buf);
 	if(enter("new date", buf, sizeof buf, mctl, kctl, nil) <= 0)
 		return;
@@ -443,6 +445,13 @@
 	Cmdbut *cmd;
 	int i;
 
+	if(ptinrect(subpt(mctl->xy, screen->r.min), viewr) && (om.buttons^mctl->buttons) == 0){
+		return;
+	}
+
+	if((om.buttons ^ mctl->buttons) == 0)
+		return;
+
 	cmd = nil;
 	for(i = 0; i < cmdbox.ncmds; i++)
 		if(ptinrect(subpt(mctl->xy, screen->r.min), cmdbox.cmds[i].r))
@@ -457,15 +466,27 @@
 mmb(void)
 {
 	enum {
+		CHGSPEED,
 		QUIT,
 	};
 	static char *items[] = {
+	 [CHGSPEED]	"change speed",
 	 [QUIT]	"quit",
 		nil,
 	};
 	static Menu menu = { .item = items };
+	char buf[128];
 
+	if((om.buttons ^ mctl->buttons) == 0)
+		return;
+
 	switch(menuhit(2, mctl, &menu, _screen)){
+	case CHGSPEED:
+		snprint(buf, sizeof buf, "%g", speed);
+		if(enter("speed (km)", buf, sizeof buf, mctl, kctl, nil) <= 0)
+			return;
+		speed = fabs(strtod(buf, nil));
+		break;
 	case QUIT:
 		threadexitsall(nil);
 	}
@@ -475,10 +496,6 @@
 void
 mouse(void)
 {
-	static Mouse om;
-
-	if((om.buttons ^ mctl->buttons) == 0)
-		return;
 	if((mctl->buttons & 1) != 0)
 		lmb();
 	if((mctl->buttons & 2) != 0)
@@ -555,17 +572,17 @@
 	static int okdown;
 
 	if(kdown & 1<<K↑)
-		placecamera(&camera, subpt3(camera.p, mulpt3(camera.bz, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, subpt3(camera.p, mulpt3(camera.bz, speed)), camera.bz, camera.by);
 	if(kdown & 1<<K↓)
-		placecamera(&camera, addpt3(camera.p, mulpt3(camera.bz, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, addpt3(camera.p, mulpt3(camera.bz, speed)), camera.bz, camera.by);
 	if(kdown & 1<<K←)
-		placecamera(&camera, subpt3(camera.p, mulpt3(camera.bx, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, subpt3(camera.p, mulpt3(camera.bx, speed)), camera.bz, camera.by);
 	if(kdown & 1<<K→)
-		placecamera(&camera, addpt3(camera.p, mulpt3(camera.bx, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, addpt3(camera.p, mulpt3(camera.bx, speed)), camera.bz, camera.by);
 	if(kdown & 1<<Krise)
-		placecamera(&camera, addpt3(camera.p, mulpt3(camera.by, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, addpt3(camera.p, mulpt3(camera.by, speed)), camera.bz, camera.by);
 	if(kdown & 1<<Kfall)
-		placecamera(&camera, subpt3(camera.p, mulpt3(camera.by, 0.1)), camera.bz, camera.by);
+		placecamera(&camera, subpt3(camera.p, mulpt3(camera.by, speed)), camera.bz, camera.by);
 	if(kdown & 1<<KR↑)
 		aimcamera(&camera, qrotate(camera.bz, camera.bx, 1*DEG));
 	if(kdown & 1<<KR↓)
@@ -618,7 +635,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s\n", argv0);
+	fprint(2, "usage: %s [-m]\n", argv0);
 	exits("usage");
 }
 
@@ -636,6 +653,7 @@
 	tmfmtinstall();
 	GEOMfmtinstall();
 	ARGBEGIN{
+	case 'm': museummode++; break;
 	case 'p': doprof++; break;
 	default: usage();
 	}ARGEND;
@@ -649,6 +667,15 @@
 	model = newmodel();
 	loadobjmodel(model, obj);
 	objfree(obj);
+	/*
+	 * normalize the vertices so that we can scale
+	 * each planet based on its radius
+	 */
+	for(i = 0; i < model->nprims; i++)
+		for(j = 0; j < model->prims[i].type+1; j++){
+			model->prims[i].v[j].p = normvec3(model->prims[i].v[j].p);
+			model->prims[i].v[j].p.w = 1;
+		}
 	scene = newscene(nil);
 	for(i = 0; i < nelem(planets); i++){
 		subject = newentity(model);
@@ -660,11 +687,13 @@
 		if(i == 0){
 			subject->p = Pt3(0,0,0,1);
 			continue;
-		}
+		}else if(museummode)
+			subject->p.x = planets[i-1].body->p.x + 1.5*planets[i-1].scale + planets[i].scale;
 	}
 	tmnow(&date, nil);
 	snprint(datestr, sizeof datestr, "%τ", tmfmt(&date, datefmt));
-	updateplanets();
+	if(!museummode)
+		updateplanets();
 
 	if(memimageinit() != 0)
 		sysfatal("memimageinit: %r");
--- a/vis.c
+++ b/vis.c
@@ -50,7 +50,7 @@
 Model *model;
 Entity *subject;
 Scene *scene;
-double θ, ω = 0;
+Quaternion orient = {1,0,0,0};
 
 Camera cams[4], *maincam;
 Camcfg camcfgs[4] = {
@@ -94,22 +94,18 @@
 	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)
 {
@@ -121,8 +117,8 @@
 	Material m;
 	Color ambient, diffuse, specular;
 
-	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));
+	sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
+	sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
 	pos = model2world(sp->su->entity, sp->v->p);
 	if(sp->v->mtl != nil){
 		m = *sp->v->mtl;
@@ -182,8 +178,8 @@
 	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));
+	sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
+	sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
 	pos = model2world(sp->su->entity, sp->v->p);
 	addvattr(sp->v, "pos", VAPoint, &pos);
 	if(sp->v->mtl != nil){
@@ -268,6 +264,8 @@
 	Point3 pos, lightdir;
 	double intens;
 
+	sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
+	sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
 	pos = model2world(sp->su->entity, sp->v->p);
 	lightdir = normvec3(subpt3(light.p, pos));
 	intens = fmax(0, dotvec3(sp->v->n, lightdir));
@@ -313,6 +311,8 @@
 Point3
 ivshader(VSparams *sp)
 {
+	sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
+	sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
 	return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
 }
 
@@ -468,7 +468,6 @@
 	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);
@@ -512,12 +511,22 @@
 				if((model->tex = readmemimage(fd)) == nil)
 					sysfatal("readmemimage: %r");
 			}
-			light.p = qrotate(light.p, Vec3(0,1,0), θ+fmod(ω*Δt/1e9, 2*PI));
 		}
 	}
 }
 
 void
+lmb(void)
+{
+	static Mouse om;
+
+	if((om.buttons^mctl->buttons) == 0)
+		qb(screen->r, om.xy, mctl->xy, &orient, nil);
+
+	om = mctl->Mouse;
+}
+
+void
 mmb(void)
 {
 	enum {
@@ -583,6 +592,8 @@
 void
 mouse(void)
 {
+	if((mctl->buttons & 1) != 0)
+		lmb();
 	if((mctl->buttons & 2) != 0)
 		mmb();
 	if((mctl->buttons & 4) != 0)
@@ -732,7 +743,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] [-ω yrot] model...\n", argv0);
+	fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] model...\n", argv0);
 	exits("usage");
 }
 
@@ -754,7 +765,6 @@
 	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();