ref: c46b7a3e97390bbe8803afbb70b307362f9123f0
parent: 702e1d92ff4e270f5be88d1b5b190c4de758a101
author: rodri <rgl@antares-labs.eu>
date: Wed May 15 10:44:58 EDT 2024
fix the qball.
--- a/dat.h
+++ b/dat.h
@@ -28,5 +28,6 @@
Scambx, Scamby, Scambz,
Sfps,
Sframes,
+ Sorient,
Se
};
--- a/fns.h
+++ b/fns.h
@@ -2,4 +2,4 @@
void *erealloc(void*, ulong);
Image *eallocimage(Display*, Rectangle, ulong, int, ulong);
Memimage *eallocmemimage(Rectangle, ulong);
-void qb(Rectangle, Point, Point, Quaternion*, Quaternion*);
+void qball(Rectangle, Point, Point, Quaternion*, Quaternion*);
--- a/mkfile
+++ b/mkfile
@@ -7,7 +7,7 @@
OFILES=\
alloc.$O\
- qb.$O\
+ qball.$O\
HFILES=dat.h fns.h
--- a/qb.c
+++ /dev/null
@@ -1,86 +1,0 @@
-/*
- * 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)));
-}
--- /dev/null
+++ b/qball.c
@@ -1,0 +1,80 @@
+/*
+ * 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"
+
+#define MIN(a, b) ((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 */
+
+ q.r = 0;
+ if(rsq > 1){ /* outside the sphere */
+ rsq = 1/sqrt(rsq);
+ q.i = p.x*rsq;
+ q.j = p.y*rsq;
+ q.k = 0;
+ }else{
+ 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
+qball(Rectangle r, Point p0, Point p1, Quaternion *orient, Quaternion *axis)
+{
+ Quaternion qdown, qdrag;
+ Point2 rmin, rmax;
+ Point2 v0, v1; /* unit sphere coords */
+ Point2 ctlcen; /* controller center */
+ double ctlrad; /* controller radius */
+
+ if(orient == nil)
+ return;
+
+ rmin = Vec2(r.min.x, r.min.y);
+ rmax = Vec2(r.max.x, r.max.y);
+ ctlcen = divpt2(addpt2(rmin, rmax), 2);
+ ctlrad = MIN(Dx(r)/2, Dy(r)/2);
+ v0 = divpt2(Vec2(p0.x-ctlcen.x, ctlcen.y-p0.y), ctlrad);
+ v1 = divpt2(Vec2(p1.x-ctlcen.x, ctlcen.y-p1.y), ctlrad);
+ qdown = mouseq(v0, axis);
+ qdrag = mulq(mouseq(v1, axis), qdown);
+ *orient = mulq(qdrag, *orient);
+}
--- a/vis.c
+++ b/vis.c
@@ -50,6 +50,7 @@
Model *model;
Entity *subject;
Scene *scene;
+Mouse om;
Quaternion orient = {1,0,0,0};
Camera cams[4], *maincam;
@@ -452,6 +453,7 @@
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);
}
@@ -518,12 +520,8 @@
void
lmb(void)
{
- static Mouse om;
-
if((om.buttons^mctl->buttons) == 0)
- qb(screen->r, om.xy, mctl->xy, &orient, nil);
-
- om = mctl->Mouse;
+ qball(screen->r, om.xy, mctl->xy, &orient, nil);
}
void
@@ -602,6 +600,7 @@
zoomin();
if((mctl->buttons & 16) != 0)
zoomout();
+ om = mctl->Mouse;
}
void