+ //
+ // [ a b c d ] [ x ]
+ // [ e f g h ] [ y ]
+ // [ i j k l ] [ z ]
+ // [ 0 0 0 1 ] [ 1 ]
+ //
+ public final float a, b, c, d, e, f, g, h, i, j, k, l;
+ public M() { this(1); }
+ public M(float scale) {
+ a = f = k = scale;
+ l = h = d = e = b = i = c = j = g = 0;
+ }
+ public M(float scalex, float scaley, float scalez) {
+ a = scalex;
+ f = scaley;
+ k = scalez;
+ l = h = d = e = b = i = c = j = g = 0;
+ }
+ public M(Vec translate) {
+ d = translate.x; h = translate.y; l = translate.z;
+ a = f = k = 1;
+ b = c = e = g = i = j = 0;
+ }
+ public M(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l) {
+ this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h; this.i = i;
+ this.j = j; this.k = k; this.l = l;
+ }
+ public M times(float x) {
+ return new M(a*x, b*x, c*x, d*x, e*x, f*x, g*x, h*x, i*x, j*x, k*x, l*x);
+ }
+ public M(Vec axis, float angle) {
+ double q = Math.cos(angle);
+ double s = Math.sin(angle);
+ double t = 1.0 - q;
+ a = (float)(q + axis.x*axis.x*t);
+ f = (float)(q + axis.y*axis.y*t);
+ k = (float)(q + axis.z*axis.z*t);
+ double tmp1 = axis.x*axis.y*t;
+ double tmp2 = axis.z*s;
+ e = (float)(tmp1 + tmp2);
+ b = (float)(tmp1 - tmp2);
+ tmp1 = axis.x*axis.z*t;
+ tmp2 = axis.y*s;
+ i = (float)(tmp1 - tmp2);
+ c = (float)(tmp1 + tmp2);
+ tmp1 = axis.y*axis.z*t;
+ tmp2 = axis.x*s;
+ j = (float)(tmp1 + tmp2);
+ g = (float)(tmp1 - tmp2);
+ d = h = l = 0;
+ }
+ public P times(P p) {
+ return newP(a*p.x + b*p.y + c*p.z + d,
+ e*p.x + f*p.y + g*p.z + h,
+ i*p.x + j*p.y + k*p.z + l);
+ }