diff options
author | rodri <rgl@antares-labs.eu> | 2023-01-29 22:27:33 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2023-01-29 22:27:33 +0000 |
commit | e70ecd9d84578dad435a39b40592f9a7cd1908d3 (patch) | |
tree | 0abadddf4f131a1aa30fed5a3a434805868fa1e6 /qb.c | |
download | qball-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 'qb.c')
-rw-r--r-- | qb.c | 96 |
1 files changed, 96 insertions, 0 deletions
@@ -0,0 +1,96 @@ +/* + * Ken Shoemake's Quaternion rotation controller + */ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include "dat.h" +#include "fns.h" + +typedef struct Point2 Point2; +struct Point2 { + double x, y; +}; + +static Point2 +Pt2(double x, double y) +{ + return (Point2){x, y}; +} + +static Point2 +addpt2(Point2 a, Point2 b) +{ + return (Point2){a.x+b.x, a.y+b.y}; +} + +static Point2 +subpt2(Point2 a, Point2 b) +{ + return (Point2){a.x-b.x, a.y-b.y}; +} + +static Point2 +divpt2(Point2 p, double s) +{ + return (Point2){p.x/s, p.y/s}; +} + +/* + * 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; + + if(rsq > 1){ + rsq = sqrt(rsq); + q.k = 0; + q.i = p.x/rsq; + q.j = p.y/rsq; + q.r = 0; + } + else{ + q.r = 0; + q.i = p.x; + q.j = p.y; + q.k = sqrt(1 - rsq); + } + if(axis != nil){ + l = q.i*axis->i + q.j*axis->j + q.k*axis->k; + q.i -= l*axis->i; + q.j -= l*axis->j; + q.k -= l*axis->k; + l = sqrt(q.i*q.i + q.j*q.j + q.k*q.k); + if(l != 0.){ + q.i /= l; + q.j /= l; + q.k /= l; + } + } + return q; +} + +void +qb(Rectangle r, Point p1, Point p2, Quaternion *orient, Quaternion *axis){ + Quaternion q, down; + Point2 rmin, rmax; + Point2 ctlcen, ctlrad; + double qx, qy; + + rmin = Pt2(r.min.x, r.min.y); + rmax = Pt2(r.max.x, r.max.y); + ctlcen = divpt2(addpt2(rmin, rmax), 2); + ctlrad = divpt2(subpt2(rmax, rmin), 2); + qx = (p1.x-ctlcen.x)/ctlrad.x; + qy = (ctlcen.y-p1.y)/ctlrad.y; + down = invq(mouseq(Pt2(qx, qy), axis)); + + q = *orient; + qx = (p2.x-ctlcen.x)/ctlrad.x; + qy = (ctlcen.y-p2.y)/ctlrad.y; + *orient = mulq(q, mulq(down, mouseq(Pt2(qx, qy), axis))); +} |