// // // Typical 3d vector math code. // By S Melax 1998-2008 // // #ifndef SM_VEC_MATH_H #define SM_VEC_MATH_H #include #include #include #include #define M_PIf (3.1415926535897932384626433832795f) inline float DegToRad(float angle_degrees) { return angle_degrees * M_PIf / 180.0f; } // returns Radians. inline float RadToDeg(float angle_radians) { return angle_radians * 180.0f / M_PIf; } // returns Degrees. #define OFFSET(Class, Member) (((char *)(&(((Class *)NULL)->Member))) - ((char *)NULL)) int argmin(const float a[], int n); int argmax(const float a[], int n); float squared(float a); float clamp(float a, const float minval = 0.0f, const float maxval = 1.0f); int clamp(int a, const int minval, const int maxval); float Round(float a, float precision); float Interpolate(const float &f0, const float &f1, float alpha); template void Swap(T &a, T &b) { T tmp = a; a = b; b = tmp; } template T Max(const T &a, const T &b) { return (a > b) ? a : b; } template T Min(const T &a, const T &b) { return (a < b) ? a : b; } //for template normalize functions: inline float squareroot(float a) { return sqrtf(a); } inline double squareroot(double a) { return sqrt(a); } //---------------------------------- //-------- 2D -------- template class vec2 { public: T x, y; inline vec2() { x = 0; y = 0; } inline vec2(const T &_x, const T &_y) { x = _x; y = _y; } inline T &operator[](int i) { return ((T *)this)[i]; } inline const T &operator[](int i) const { return ((T *)this)[i]; } }; typedef vec2 int2; typedef vec2 float2; template inline int operator==(const vec2 &a, const vec2 &b) { return (a.x == b.x && a.y == b.y); } template inline vec2 operator-(const vec2 &a, const vec2 &b) { return vec2(a.x - b.x, a.y - b.y); } template inline vec2 operator+(const vec2 &a, const vec2 &b) { return float2(a.x + b.x, a.y + b.y); } //--------- 3D --------- template class vec3 { public: T x, y, z; inline vec3() { x = 0; y = 0; z = 0; }; inline vec3(const T &_x, const T &_y, const T &_z) { x = _x; y = _y; z = _z; }; inline T &operator[](int i) { return ((T *)this)[i]; } inline const T &operator[](int i) const { return ((T *)this)[i]; } }; typedef vec3 int3; typedef vec3 short3; typedef vec3 float3; // due to ambiguity there is no overloaded operators for v3*v3 use dot,cross,outerprod,cmul template inline int operator==(const vec3 &a, const vec3 &b) { return (a.x == b.x && a.y == b.y && a.z == b.z); } template inline int operator!=(const vec3 &a, const vec3 &b) { return !(a == b); } template inline vec3 operator+(const vec3 &a, const vec3 &b) { return vec3(a.x + b.x, a.y + b.y, a.z + b.z); } template inline vec3 operator-(const vec3 &a, const vec3 &b) { return vec3(a.x - b.x, a.y - b.y, a.z - b.z); } template inline vec3 operator-(const vec3 &v) { return vec3(-v.x, -v.y, -v.z); } template inline vec3 operator*(const vec3 &v, const T &s) { return vec3(v.x * s, v.y * s, v.z * s); } template inline vec3 operator*(T s, const vec3 &v) { return v * s; } template inline vec3 operator/(const vec3 &v, T s) { return vec3(v.x / s, v.y / s, v.z / s); } template inline T dot(const vec3 &a, const vec3 &b) { return a.x * b.x + a.y * b.y + a.z * b.z; } template inline vec3 cmul(const vec3 &a, const vec3 &b) { return vec3(a.x * b.x, a.y * b.y, a.z * b.z); } template inline vec3 cross(const vec3 &a, const vec3 &b) { return vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } template inline T magnitude(const vec3 &v) { return squareroot(dot(v, v)); } template inline vec3 normalize(const vec3 &v) { return v / magnitude(v); } template inline vec3 &operator+=(vec3 &a, const vec3 &b) { a.x += b.x; a.y += b.y; a.z += b.z; return a; } template inline vec3 &operator-=(vec3 &a, const vec3 &b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; return a; } template inline vec3 &operator*=(vec3 &v, T s) { v.x *= s; v.y *= s; v.z *= s; return v; } template inline vec3 &operator/=(vec3 &v, T s) { v.x /= s; v.y /= s; v.z /= s; return v; } float3 safenormalize(const float3 &v); float3 vabs(const float3 &v); float3 Interpolate(const float3 &v0, const float3 &v1, float alpha); float3 Round(const float3 &a, float precision); template inline vec3 VectorMin(const vec3 &a, const vec3 &b) { return vec3(Min(a.x, b.x), Min(a.y, b.y), Min(a.z, b.z)); } template inline vec3 VectorMax(const vec3 &a, const vec3 &b) { return vec3(Max(a.x, b.x), Max(a.y, b.y), Max(a.z, b.z)); } int overlap(const float3 &bmina, const float3 &bmaxa, const float3 &bminb, const float3 &bmaxb); template class mat3x3 { public: vec3 x, y, z; // the 3 rows of the Matrix inline mat3x3() {} inline mat3x3(const T &xx, const T &xy, const T &xz, const T &yx, const T &yy, const T &yz, const T &zx, const T &zy, const T &zz) : x(xx, xy, xz), y(yx, yy, yz), z(zx, zy, zz) {} inline mat3x3(const vec3 &_x, const vec3 &_y, const vec3 &_z) : x(_x), y(_y), z(_z) {} inline vec3 &operator[](int i) { return (&x)[i]; } inline const vec3 &operator[](int i) const { return (&x)[i]; } inline T &operator()(int r, int c) { return ((&x)[r])[c]; } inline const T &operator()(int r, int c) const { return ((&x)[r])[c]; } }; typedef mat3x3 float3x3; float3x3 Transpose(const float3x3 &m); template vec3 operator*(const vec3 &v, const mat3x3 &m) { return vec3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z)); } float3 operator*(const float3x3 &m, const float3 &v); float3x3 operator*(const float3x3 &m, const float &s); float3x3 operator*(const float3x3 &ma, const float3x3 &mb); float3x3 operator/(const float3x3 &a, const float &s); float3x3 operator+(const float3x3 &a, const float3x3 &b); float3x3 operator-(const float3x3 &a, const float3x3 &b); float3x3 &operator+=(float3x3 &a, const float3x3 &b); float3x3 &operator-=(float3x3 &a, const float3x3 &b); float3x3 &operator*=(float3x3 &a, const float &s); float Determinant(const float3x3 &m); float3x3 Inverse(const float3x3 &a); // its just 3x3 so we simply do that cofactor method float3x3 outerprod(const float3 &a, const float3 &b); //-------- 4D Math -------- template class vec4 { public: T x, y, z, w; inline vec4() { x = 0; y = 0; z = 0; w = 0; }; inline vec4(const T &_x, const T &_y, const T &_z, const T &_w) { x = _x; y = _y; z = _z; w = _w; } inline vec4(const vec3 &v, const T &_w) { x = v.x; y = v.y; z = v.z; w = _w; } //operator float *() { return &x;}; T &operator[](int i) { return ((T *)this)[i]; } const T &operator[](int i) const { return ((T *)this)[i]; } inline const vec3 &xyz() const { return *((vec3 *)this); } inline vec3 &xyz() { return *((vec3 *)this); } }; typedef vec4 float4; typedef vec4 int4; typedef vec4 byte4; template inline int operator==(const vec4 &a, const vec4 &b) { return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); } template inline int operator!=(const vec4 &a, const vec4 &b) { return !(a == b); } template inline vec4 operator+(const vec4 &a, const vec4 &b) { return vec4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } template inline vec4 operator-(const vec4 &a, const vec4 &b) { return vec4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } template inline vec4 operator-(const vec4 &v) { return vec4(-v.x, -v.y, -v.z, -v.w); } template inline vec4 operator*(const vec4 &v, const T &s) { return vec4(v.x * s, v.y * s, v.z * s, v.w * s); } template inline vec4 operator*(T s, const vec4 &v) { return v * s; } template inline vec4 operator/(const vec4 &v, T s) { return vec4(v.x / s, v.y / s, v.z / s, v.w / s); } template inline T dot(const vec4 &a, const vec4 &b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } template inline vec4 cmul(const vec4 &a, const vec4 &b) { return vec4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } template inline vec4 &operator+=(vec4 &a, const vec4 &b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; return a; } template inline vec4 &operator-=(vec4 &a, const vec4 &b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; return a; } template inline vec4 &operator*=(vec4 &v, T s) { v.x *= s; v.y *= s; v.z *= s; v.w *= s; return v; } template inline vec4 &operator/=(vec4 &v, T s) { v.x /= s; v.y /= s; v.z /= s; v.w /= s; return v; } template inline T magnitude(const vec4 &v) { return squareroot(dot(v, v)); } template inline vec4 normalize(const vec4 &v) { return v / magnitude(v); } struct D3DXMATRIX; template class mat4x4 { public: vec4 x, y, z, w; // the 4 rows inline mat4x4() {} inline mat4x4(const vec4 &_x, const vec4 &_y, const vec4 &_z, const vec4 &_w) : x(_x), y(_y), z(_z), w(_w) {} inline mat4x4(const T &m00, const T &m01, const T &m02, const T &m03, const T &m10, const T &m11, const T &m12, const T &m13, const T &m20, const T &m21, const T &m22, const T &m23, const T &m30, const T &m31, const T &m32, const T &m33) : x(m00, m01, m02, m03), y(m10, m11, m12, m13), z(m20, m21, m22, m23), w(m30, m31, m32, m33) {} inline vec4 &operator[](int i) { assert(i >= 0 && i < 4); return (&x)[i]; } inline const vec4 &operator[](int i) const { assert(i >= 0 && i < 4); return (&x)[i]; } inline T &operator()(int r, int c) { assert(r >= 0 && r < 4 && c >= 0 && c < 4); return ((&x)[r])[c]; } inline const T &operator()(int r, int c) const { assert(r >= 0 && r < 4 && c >= 0 && c < 4); return ((&x)[r])[c]; } inline operator T *() { return &x.x; } inline operator const T *() const { return &x.x; } operator struct D3DXMATRIX *() { return (struct D3DXMATRIX *)this; } operator const struct D3DXMATRIX *() const { return (struct D3DXMATRIX *)this; } }; typedef mat4x4 float4x4; float4x4 operator*(const float4x4 &a, const float4x4 &b); float4 operator*(const float4 &v, const float4x4 &m); float4x4 Inverse(const float4x4 &m); float4x4 MatrixRigidInverse(const float4x4 &m); float4x4 MatrixTranspose(const float4x4 &m); float4x4 MatrixPerspectiveFov(float fovy, float Aspect, float zn, float zf); float4x4 MatrixTranslation(const float3 &t); float4x4 MatrixRotationZ(const float angle_radians); float4x4 MatrixLookAt(const float3 &eye, const float3 &at, const float3 &up); int operator==(const float4x4 &a, const float4x4 &b); //-------- Quaternion ------------ template class quaternion : public vec4 { public: inline quaternion() { this->x = this->y = this->z = 0.0f; this->w = 1.0f; } inline quaternion(const T &_x, const T &_y, const T &_z, const T &_w) { this->x = _x; this->y = _y; this->z = _z; this->w = _w; } inline explicit quaternion(const vec4 &v) : vec4(v) {} T angle() const { return acosf(this->w) * 2.0f; } vec3 axis() const { vec3 a(this->x, this->y, this->z); if (fabsf(angle()) < 0.0000001f) return vec3(1, 0, 0); return a * (1 / sinf(angle() / 2.0f)); } inline vec3 xdir() const { return vec3(1 - 2 * (this->y * this->y + this->z * this->z), 2 * (this->x * this->y + this->w * this->z), 2 * (this->x * this->z - this->w * this->y)); } inline vec3 ydir() const { return vec3(2 * (this->x * this->y - this->w * this->z), 1 - 2 * (this->x * this->x + this->z * this->z), 2 * (this->y * this->z + this->w * this->x)); } inline vec3 zdir() const { return vec3(2 * (this->x * this->z + this->w * this->y), 2 * (this->y * this->z - this->w * this->x), 1 - 2 * (this->x * this->x + this->y * this->y)); } inline mat3x3 getmatrix() const { return mat3x3(xdir(), ydir(), zdir()); } //operator float3x3() { return getmatrix(); } void Normalize(); }; template inline quaternion quatfrommat(const mat3x3 &m) { T magw = m[0][0] + m[1][1] + m[2][2]; T magxy; T magzw; vec3 pre; vec3 prexy; vec3 prezw; quaternion postxy; quaternion postzw; quaternion post; int wvsz = (magw > m[2][2]); magzw = (wvsz) ? magw : m[2][2]; prezw = (wvsz) ? vec3(1.0f, 1.0f, 1.0f) : vec3(-1.0f, -1.0f, 1.0f); postzw = (wvsz) ? quaternion(0.0f, 0.0f, 0.0f, 1.0f) : quaternion(0.0f, 0.0f, 1.0f, 0.0f); int xvsy = (m[0][0] > m[1][1]); magxy = (xvsy) ? m[0][0] : m[1][1]; prexy = (xvsy) ? vec3(1.0f, -1.0f, -1.0f) : vec3(-1.0f, 1.0f, -1.0f); postxy = (xvsy) ? quaternion(1.0f, 0.0f, 0.0f, 0.0f) : quaternion(0.0f, 1.0f, 0.0f, 0.0f); int zwvsxy = (magzw > magxy); pre = (zwvsxy) ? prezw : prexy; post = (zwvsxy) ? postzw : postxy; T t = pre.x * m[0][0] + pre.y * m[1][1] + pre.z * m[2][2] + 1.0f; T s = 1 / sqrt(t) * 0.5f; quaternion qp; qp.x = (pre.y * m[1][2] - pre.z * m[2][1]) * s; qp.y = (pre.z * m[2][0] - pre.x * m[0][2]) * s; qp.z = (pre.x * m[0][1] - pre.y * m[1][0]) * s; qp.w = t * s; return qp * post; } typedef quaternion Quaternion; inline Quaternion QuatFromAxisAngle(const float3 &_v, float angle_radians) { float3 v = normalize(_v) * sinf(angle_radians / 2.0f); return Quaternion(v.x, v.y, v.z, cosf(angle_radians / 2.0f)); } template inline quaternion Conjugate(const quaternion &q) { return quaternion(-q.x, -q.y, -q.z, q.w); } template inline quaternion Inverse(const quaternion &q) { return Conjugate(q); } template inline quaternion normalize(const quaternion &a) { return quaternion(normalize((vec4 &)a)); } template inline quaternion &operator*=(quaternion &a, T s) { return (quaternion &)((vec4 &)a *= s); } template inline quaternion operator*(const quaternion &a, float s) { return quaternion((vec4 &)a * s); } template inline quaternion operator+(const quaternion &a, const quaternion &b) { return quaternion((vec4 &)a + (vec4 &)b); } template inline quaternion operator-(const quaternion &a, const quaternion &b) { return quaternion((vec4 &)a - (vec4 &)b); } template inline quaternion operator-(const quaternion &b) { return quaternion(-(vec4 &)b); } template inline quaternion operator*(const quaternion &a, const quaternion &b) { return quaternion( a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, //x a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, //y a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, //z a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z); //w } float3 rotate(const Quaternion &q, const float3 &v); //float3 operator*( const Quaternion& q, const float3& v ); //float3 operator*( const float3& v, const Quaternion& q ); Quaternion slerp(const Quaternion &a, const Quaternion &b, float t); Quaternion Interpolate(const Quaternion &q0, const Quaternion &q1, float t); Quaternion RotationArc(float3 v0, float3 v1); // returns quat q where q*v0*q^-1=v1 float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v); inline Quaternion QuatFromMat(const float3 &t, const float3 &b, const float3 &n) { return normalize(quatfrommat(float3x3(t, b, n))); } //---------------- Pose ------------------ class Pose { public: float3 position; Quaternion orientation; Pose() {} Pose(const float3 &p, const Quaternion &q) : position(p), orientation(q) {} Pose &pose() { return *this; } const Pose &pose() const { return *this; } }; inline float3 operator*(const Pose &a, const float3 &v) { return a.position + rotate(a.orientation, v); } inline Pose operator*(const Pose &a, const Pose &b) { return Pose(a.position + rotate(a.orientation, b.position), a.orientation * b.orientation); } inline Pose Inverse(const Pose &a) { Quaternion q = Inverse(a.orientation); return Pose(rotate(q, -a.position), q); } inline Pose slerp(const Pose &p0, const Pose &p1, float t) { return Pose(p0.position * (1.0f - t) + p1.position * t, slerp(p0.orientation, p1.orientation, t)); } inline float4x4 MatrixFromPose(const Pose &pose) { return MatrixFromQuatVec(pose.orientation, pose.position); } //------ Euler Angle ----- Quaternion YawPitchRoll(float yaw, float pitch, float roll); float Yaw(const Quaternion &q); float Pitch(const Quaternion &q); float Roll(const Quaternion &q); float Yaw(const float3 &v); float Pitch(const float3 &v); //------- Plane ---------- class Plane : public float4 { public: float3 &normal() { return xyz(); } const float3 &normal() const { return xyz(); } float &dist() { return w; } // distance below origin - the D from plane equasion Ax+By+Cz+D=0 const float &dist() const { return w; } // distance below origin - the D from plane equasion Ax+By+Cz+D=0 Plane(const float3 &n, float d) : float4(n, d) {} Plane() { dist() = 0; } explicit Plane(const float4 &v) : float4(v) {} }; Plane Transform(const Plane &p, const float3 &translation, const Quaternion &rotation); inline Plane PlaneFlip(const Plane &p) { return Plane(-p.normal(), -p.dist()); } inline int operator==(const Plane &a, const Plane &b) { return (a.normal() == b.normal() && a.dist() == b.dist()); } inline int coplanar(const Plane &a, const Plane &b) { return (a == b || a == PlaneFlip(b)); } float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1); float3 PlaneProject(const Plane &plane, const float3 &point); float3 PlanesIntersection(const Plane &p0, const Plane &p1, const Plane &p2); float3 PlanesIntersection(const Plane *planes, int planes_count, const float3 &seed = float3(0, 0, 0)); int Clip(const Plane &p, const float3 *verts_in, int count, float *verts_out); // verts_out must be preallocated with sufficient size >= count+1 or more if concave int ClipPolyPoly(const float3 &normal, const float3 *clipper, int clipper_count, const float3 *verts_in, int in_count, float3 *scratch); //scratch must be preallocated //--------- Utility Functions ------ float3 PlaneLineIntersection(const float3 &normal, const float dist, const float3 &p0, const float3 &p1); float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a); // projects a onto infinite line p0p1 float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a); int BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax); int BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax, float3 *impact); float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint = NULL, float3 *vpoint = NULL); float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2); float3 NormalOf(const float3 *vert, const int n); Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir0, const float3 &dir1); int Clip(const float3 &plane_normal, float plane_dist, const float3 *verts_in, int count, float *verts_out); // verts_out must be preallocated with sufficient size >= count+1 or more if concave int ClipPolyPoly(const float3 &normal, const float3 *clipper, int clipper_count, const float3 *verts_in, int in_count, float3 *scratch); //scratch must be preallocated float3 Diagonal(const float3x3 &M); Quaternion Diagonalizer(const float3x3 &A); float3 Orth(const float3 &v); int SolveQuadratic(float a, float b, float c, float *ta, float *tb); // if true returns roots ta,tb where ta<=tb int HitCheckPoly(const float3 *vert, const int n, const float3 &v0, const float3 &v1, float3 *impact = NULL, float3 *normal = NULL); int HitCheckRaySphere(const float3 &sphereposition, float radius, const float3 &_v0, const float3 &_v1, float3 *impact, float3 *normal); int HitCheckRayCylinder(const float3 &p0, const float3 &p1, float radius, const float3 &_v0, const float3 &_v1, float3 *impact, float3 *normal); int HitCheckSweptSphereTri(const float3 &p0, const float3 &p1, const float3 &p2, float radius, const float3 &v0, const float3 &_v1, float3 *impact, float3 *normal); void BoxLimits(const float3 *verts, int verts_count, float3 &bmin_out, float3 &bmax_out); void BoxLimits(const float4 *verts, int verts_count, float3 &bmin_out, float3 &bmax_out); template inline int maxdir(const T *p, int count, const T &dir) { assert(count); int m = 0; for (int i = 1; i < count; i++) { if (dot(p[i], dir) > dot(p[m], dir)) m = i; } return m; } float3 CenterOfMass(const float3 *vertices, const int3 *tris, const int count); float3x3 Inertia(const float3 *vertices, const int3 *tris, const int count, const float3 &com = float3(0, 0, 0)); float Volume(const float3 *vertices, const int3 *tris, const int count); int calchull(float3 *verts, int verts_count, int3 *&tris_out, int &tris_count, int vlimit); // computes convex hull see hull.cpp #endif // VEC_MATH_H