From 0d28d5950b232bea02f45b666a3eb7fcb159b5df Mon Sep 17 00:00:00 2001 From: gered Date: Fri, 22 Apr 2011 16:04:05 -0400 Subject: [PATCH] adding more math/common helper stuff --- MeshConverter/MeshConverter.vcxproj | 4 + MeshConverter/src/common.h | 27 + MeshConverter/src/geometry/common.h | 19 + MeshConverter/src/geometry/matrix4x4.h | 1030 +++++++++++++++++++++++ MeshConverter/src/geometry/quaternion.h | 491 +++++++++++ MeshConverter/src/geometry/vector2.h | 231 ++++- MeshConverter/src/geometry/vector3.h | 332 ++++---- 7 files changed, 1976 insertions(+), 158 deletions(-) create mode 100644 MeshConverter/src/common.h create mode 100644 MeshConverter/src/geometry/common.h create mode 100644 MeshConverter/src/geometry/matrix4x4.h create mode 100644 MeshConverter/src/geometry/quaternion.h diff --git a/MeshConverter/MeshConverter.vcxproj b/MeshConverter/MeshConverter.vcxproj index 4f76d12..91b072a 100644 --- a/MeshConverter/MeshConverter.vcxproj +++ b/MeshConverter/MeshConverter.vcxproj @@ -90,6 +90,10 @@ + + + + diff --git a/MeshConverter/src/common.h b/MeshConverter/src/common.h new file mode 100644 index 0000000..e31b704 --- /dev/null +++ b/MeshConverter/src/common.h @@ -0,0 +1,27 @@ +#ifndef __COMMON_H_INCLUDED__ +#define __COMMON_H_INCLUDED__ + +#include + +#if !defined(TRUE) && !defined(FALSE) +typedef int32_t BOOL; +const BOOL TRUE = 1; +const BOOL FALSE = 0; +#endif + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = NULL; } +#endif + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if (x) { delete (x); (x) = NULL; } +#endif + +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if (x) { delete [] (x); (x) = NULL; } +#endif + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#endif \ No newline at end of file diff --git a/MeshConverter/src/geometry/common.h b/MeshConverter/src/geometry/common.h new file mode 100644 index 0000000..d5060fa --- /dev/null +++ b/MeshConverter/src/geometry/common.h @@ -0,0 +1,19 @@ +#ifndef __GEOMETRY_COMMON_H_INCLUDED__ +#define __GEOMETRY_COMMON_H_INCLUDED__ + +#include + +#define PI 3.141593f +#define PI_OVER_180 (PI / 180.0f) + +#define DEG_TO_RAD(x) ((x) * PI_OVER_180) +#define RAD_TO_DEG(x) ((x) * (1.0f / (PI_OVER_180))) + +#define TOLERANCE 0.00001f +#define IS_CLOSE_ENOUGH(a, b) (fabs((a - b) / ((b == 0.0f) ? 1.0f : b)) < EPSILON) + +#define EPSILON 0.0005f + +#define ISPOWEROF2(x) (((x) != 0) && !((x) & ((x) - 1))) + +#endif diff --git a/MeshConverter/src/geometry/matrix4x4.h b/MeshConverter/src/geometry/matrix4x4.h new file mode 100644 index 0000000..b6e4a42 --- /dev/null +++ b/MeshConverter/src/geometry/matrix4x4.h @@ -0,0 +1,1030 @@ +#ifndef __GEOMETRY_MATRIX4X4_H_INCLUDED__ +#define __GEOMETRY_MATRIX4X4_H_INCLUDED__ + +#include +#include "common.h" +#include "vector3.h" + +typedef enum +{ + _11 = 0, + _12 = 4, + _13 = 8, + _14 = 12, + _21 = 1, + _22 = 5, + _23 = 9, + _24 = 13, + _31 = 2, + _32 = 6, + _33 = 10, + _34 = 14, + _41 = 3, + _42 = 7, + _43 = 11, + _44 = 15 +} MATRIX_ELEMENTS; + +/** + * Represents a 4x4 column-major Matrix and provides common methods for + * matrix math. + *

Referenced/based on code from:

+ *
    + *
  • 3D Math Primer for Graphics and Game Development (Dunn & Parberry, 2002)
  • + *
  • http://www.dhpoware.com/source/mathlib.html
  • + *
  • http://www.songho.ca/opengl/gl_transform.html
  • + *
  • http://www.opengl.org/sdk/docs/man/
  • + *
+ * @author Gered + */ +class Matrix4x4 +{ +public: + Matrix4x4() {} + + Matrix4x4( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44 + ); + + Matrix4x4(const float *mv); + + ~Matrix4x4() {} + + void Set( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44 + ); + float GetDeterminant() const; + Vector3 GetForward() const; + Vector3 GetBackward() const; + Vector3 GetLeft() const; + Vector3 GetRight() const; + Vector3 GetUp() const; + Vector3 GetDown() const; + Vector3 GetTranslation() const; + + static Matrix4x4 Identity(); + static Matrix4x4 CreateBillboard(const Vector3 &objectPosition, const Vector3 &cameraPosition, const Vector3 &cameraUp, const Vector3 &cameraForward); + static Matrix4x4 CreateCylindricalBillboard(const Vector3 &objectPosition, const Vector3 &cameraPosition, const Vector3 &cameraForward, const Vector3 &axis); + static Matrix4x4 CreateFromEulerAngles(float x, float y, float z); + static Matrix4x4 CreateLookAt(const Vector3 &cameraPosition, const Vector3 &cameraTarget, const Vector3 &cameraUp); + static Matrix4x4 CreateOrthographic(float left, float right, float bottom, float top, float near_, float far_); + static Matrix4x4 CreatePerspective(float left, float right, float bottom, float top, float near_, float far_); + static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float near_, float far_); + static Matrix4x4 CreateRotation(float angle, const Vector3 &axis); + static Matrix4x4 CreateRotationX(float angle); + static Matrix4x4 CreateRotationY(float angle); + static Matrix4x4 CreateRotationZ(float angle); + static Matrix4x4 CreateScale(float x, float y, float z); + static Matrix4x4 CreateTranslation(float x, float y, float z); + static Matrix4x4 CreateWorld(const Vector3 &position, const Vector3 &forward, const Vector3 &up); + static Matrix4x4 Inverse(const Matrix4x4 &m); + static Matrix4x4 Transpose(const Matrix4x4 &m); + + float m[16]; +}; + +Matrix4x4 operator+(const Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 &operator+=(Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 operator-(const Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 &operator-=(Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 operator*(const Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 &operator*=(Matrix4x4 &left, const Matrix4x4 &right); +Matrix4x4 operator*(const Matrix4x4 &left, float right); +Matrix4x4 &operator*=(Matrix4x4 &left, float right); +Vector3 operator*(const Vector3 &left, const Matrix4x4 &right); + +#define IDENTITY_MATRIX Matrix4x4::Identity() + +inline Matrix4x4::Matrix4x4( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44 + ) +{ + m[_11] = m11; + m[_12] = m12; + m[_13] = m13; + m[_14] = m14; + m[_21] = m21; + m[_22] = m22; + m[_23] = m23; + m[_24] = m24; + m[_31] = m31; + m[_32] = m32; + m[_33] = m33; + m[_34] = m34; + m[_41] = m41; + m[_42] = m42; + m[_43] = m43; + m[_44] = m44; +} + +inline Matrix4x4::Matrix4x4(const float *mv) +{ + m[_11] = mv[_11]; + m[_12] = mv[_12]; + m[_13] = mv[_13]; + m[_14] = mv[_14]; + m[_21] = mv[_21]; + m[_22] = mv[_22]; + m[_23] = mv[_23]; + m[_24] = mv[_24]; + m[_31] = mv[_31]; + m[_32] = mv[_32]; + m[_33] = mv[_33]; + m[_34] = mv[_34]; + m[_41] = mv[_41]; + m[_42] = mv[_42]; + m[_43] = mv[_43]; + m[_44] = mv[_44]; +} + +inline void Matrix4x4::Set( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44 + ) +{ + m[_11] = m11; + m[_12] = m12; + m[_13] = m13; + m[_14] = m14; + m[_21] = m21; + m[_22] = m22; + m[_23] = m23; + m[_24] = m24; + m[_31] = m31; + m[_32] = m32; + m[_33] = m33; + m[_34] = m34; + m[_41] = m41; + m[_42] = m42; + m[_43] = m43; + m[_44] = m44; +} + +/** + * Gets the determinant of the matrix. + * @return the determinant + */ +inline float Matrix4x4::GetDeterminant() const +{ + return + (m[_11] * m[_22] - m[_21] * m[_12]) * + (m[_33] * m[_44] - m[_43] * m[_34]) - + (m[_11] * m[_32] - m[_31] * m[_12]) * + (m[_23] * m[_44] - m[_43] * m[_24]) + + (m[_11] * m[_42] - m[_41] * m[_12]) * + (m[_23] * m[_34] - m[_33] * m[_24]) + + (m[_21] * m[_32] - m[_31] * m[_22]) * + (m[_13] * m[_44] - m[_43] * m[_14]) - + (m[_21] * m[_42] - m[_41] * m[_22]) * + (m[_13] * m[_34] - m[_33] * m[_14]) + + (m[_31] * m[_42] - m[_41] * m[_32]) * + (m[_13] * m[_24] - m[_23] * m[_14]); +} + +/** + * @return Vector3 the forward vector (z-axis) + */ +inline Vector3 Matrix4x4::GetForward() const +{ + return Vector3(m[_13], m[_23], m[_33]); +} + +/** + * @return Vector3 the backward vector (inverse z-axis) + */ +inline Vector3 Matrix4x4::GetBackward() const +{ + return Vector3(-m[_13], -m[_23], -m[_33]); +} + +/** + * @return Vector3 the left vector (x-axis) + */ +inline Vector3 Matrix4x4::GetLeft() const +{ + return Vector3(m[_11], m[_21], m[_31]); +} + +/** + * @return Vector3 the right vector (inverse x-axis) + */ +inline Vector3 Matrix4x4::GetRight() const +{ + return Vector3(-m[_11], -m[_21], -m[_31]); +} + +/** + * @return Vector3 the up vector (y-axis) + */ +inline Vector3 Matrix4x4::GetUp() const +{ + return Vector3(m[_12], m[_22], m[_32]); +} + +/** + * @return Vector3 the down vector (inverse y-axis) + */ +inline Vector3 Matrix4x4::GetDown() const +{ + return Vector3(-m[_12], -m[_22], -m[_32]); +} + +/** + * @return Vector3 the translation vector + */ +inline Vector3 Matrix4x4::GetTranslation() const +{ + return Vector3(m[_14], m[_24], m[_34]); +} + +/** + * @return Matrix4x4 identity matrix + */ +inline Matrix4x4 Matrix4x4::Identity() +{ + Matrix4x4 identity; + + identity.m[_11] = 1.0f; + identity.m[_12] = 0.0f; + identity.m[_13] = 0.0f; + identity.m[_14] = 0.0f; + identity.m[_21] = 0.0f; + identity.m[_22] = 1.0f; + identity.m[_23] = 0.0f; + identity.m[_24] = 0.0f; + identity.m[_31] = 0.0f; + identity.m[_32] = 0.0f; + identity.m[_33] = 1.0f; + identity.m[_34] = 0.0f; + identity.m[_41] = 0.0f; + identity.m[_42] = 0.0f; + identity.m[_43] = 0.0f; + identity.m[_44] = 1.0f; + + return identity; +} + +/** + * Constructs a point billboard (spherical billboard) transformation matrix. + * @param objectPosition the position of the billboard object + * @param cameraPosition the position of the camera viewing the billboard + * @param cameraUp the up vector of the camera + * @param cameraForward the forward vector of the camera + * @return a billboard transformation matrix + */ +inline Matrix4x4 Matrix4x4::CreateBillboard(const Vector3 &objectPosition, const Vector3 &cameraPosition, const Vector3 &cameraUp, const Vector3 &cameraForward) +{ + Vector3 forward = objectPosition - cameraPosition; + float forwardLengthSquared = Vector3::LengthSquared(forward); + if (forwardLengthSquared < 0.0001f) + forward = -cameraForward; + else + forward = forward * (1.0f / (sqrtf(forwardLengthSquared))); + + Vector3 left = Vector3::Normalize(Vector3::Cross(cameraUp, forward)); + Vector3 up = Vector3::Cross(forward, left); + + Matrix4x4 out; + + out.m[_11] = left.x; + out.m[_21] = left.y; + out.m[_31] = left.z; + out.m[_41] = 0.0f; + + out.m[_12] = up.x; + out.m[_22] = up.y; + out.m[_32] = up.z; + out.m[_42] = 0.0f; + + out.m[_13] = forward.x; + out.m[_23] = forward.y; + out.m[_33] = forward.z; + out.m[_43] = 0.0f; + + out.m[_14] = objectPosition.x; + out.m[_24] = objectPosition.y; + out.m[_34] = objectPosition.z; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Creates a transformation matrix for a billboard that is constrained to + * rotate about an arbitrary axis. + * @param objectPosition the position of the billboard object + * @param cameraPosition the position of the camera viewing the billboard + * @param cameraForward the forward vector of the camera + * @param axis the axis that the billboard is to rotate about + * @return a billboard transformation matrix + */ +inline Matrix4x4 Matrix4x4::CreateCylindricalBillboard(const Vector3 &objectPosition, const Vector3 &cameraPosition, const Vector3 &cameraForward, const Vector3 &axis) +{ + Vector3 temp = objectPosition - cameraPosition; + float lengthSquared = Vector3::LengthSquared(temp); + if (lengthSquared < 0.0001f) + temp = -cameraForward; + else + temp = temp * (1.0f / (sqrtf(lengthSquared))); + + Vector3 up = axis; + Vector3 forward; + Vector3 left; + + float dot = Vector3::Dot(axis, temp); + if (fabs(dot) > 0.9982547f) + { + dot = Vector3::Dot(axis, FORWARD); + if (fabs(dot) > 0.9982547f) + forward = RIGHT; + else + forward = FORWARD; + + left = Vector3::Normalize(Vector3::Cross(axis, forward)); + forward = Vector3::Normalize(Vector3::Cross(left, axis)); + } + else + { + left = Vector3::Normalize(Vector3::Cross(axis, temp)); + forward = Vector3::Normalize(Vector3::Cross(left, up)); + } + + Matrix4x4 out; + + out.m[_11] = left.x; + out.m[_21] = left.y; + out.m[_31] = left.z; + out.m[_41] = 0.0f; + + out.m[_12] = up.x; + out.m[_22] = up.y; + out.m[_32] = up.z; + out.m[_42] = 0.0f; + + out.m[_13] = forward.x; + out.m[_23] = forward.y; + out.m[_33] = forward.z; + out.m[_43] = 0.0f; + + out.m[_14] = objectPosition.x; + out.m[_24] = objectPosition.y; + out.m[_34] = objectPosition.z; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a rotation matrix from euler angles (specified in radians). + * @param x the x angle + * @param y the y angle + * @param z the z angle + * @return a rotation matrix representing the provided angles + */ +inline Matrix4x4 Matrix4x4::CreateFromEulerAngles(float x, float y, float z) +{ + Matrix4x4 rotateZ = CreateRotationZ(z); + Matrix4x4 rotateY = CreateRotationY(y); + Matrix4x4 rotateX = CreateRotationX(x); + + // "right-to-left" column-major matrix concatenation + return rotateZ * rotateY * rotateX; +} + +/** + * Constructs a modelview matrix. This constructs the same matrix as a call + * to gluLookAt. + * @param cameraPosition position of the camera (eye) + * @param cameraTarget the direction the camera is pointing (center) + * @param cameraUp the up direction relative to the camera + * @return a modelview matrix + */ +inline Matrix4x4 Matrix4x4::CreateLookAt(const Vector3 &cameraPosition, const Vector3 &cameraTarget, const Vector3 &cameraUp) +{ + Matrix4x4 out; + + // build basic lookat matrix without translation component included + Vector3 forward = Vector3::Normalize(cameraTarget - cameraPosition); + Vector3 left = Vector3::Normalize(Vector3::Cross(forward, cameraUp)); + Vector3 up = Vector3::Cross(left, forward); + + out.m[_11] = left.x; + out.m[_21] = up.x; + out.m[_31] = -forward.x; + out.m[_41] = 0.0f; + + out.m[_12] = left.y; + out.m[_22] = up.y; + out.m[_32] = -forward.y; + out.m[_42] = 0.0f; + + out.m[_13] = left.z; + out.m[_23] = up.z; + out.m[_33] = -forward.z; + out.m[_43] = 0.0f; + + out.m[_14] = 0.0f; + out.m[_24] = 0.0f; + out.m[_34] = 0.0f; + out.m[_44] = 1.0f; + + // multiply the translation into the lookat matrix + // this matrix multiplication is simplified so that we're only multiplying components that can actually affect the result + // out = Matrix4x4::CreateTranslation(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z) * out; + out.m[_14] = out.m[_11] * -cameraPosition.x + out.m[_12] * -cameraPosition.y + out.m[_13] * -cameraPosition.z + out.m[_14]; + out.m[_24] = out.m[_21] * -cameraPosition.x + out.m[_22] * -cameraPosition.y + out.m[_23] * -cameraPosition.z + out.m[_24]; + out.m[_34] = out.m[_31] * -cameraPosition.x + out.m[_32] * -cameraPosition.y + out.m[_33] * -cameraPosition.z + out.m[_34]; + out.m[_44] = out.m[_41] * -cameraPosition.x + out.m[_42] * -cameraPosition.y + out.m[_43] * -cameraPosition.z + out.m[_44]; + + return out; +} + +/** + * Creates an orthogonal projection matrix. This is equivalent to a matrix + * created by using OpenGL's glOrtho() function. + * @param left coordinate of the left vertical clipping plane + * @param right coordinate of the right vertical clipping plane + * @param bottom coordinate of the bottom horizontal clipping plane + * @param top coordinate of the top horizontal clipping plane + * @param near near clipping plane distance (negative value is behind the viewer) + * @param far far clipping plane distance (negative value is behind the viewer) + * @return an orthogonal projection matrix + */ +inline Matrix4x4 Matrix4x4::CreateOrthographic(float left, float right, float bottom, float top, float near_, float far_) +{ + Matrix4x4 out; + + out.m[_11] = 2.0f / (right - left); + out.m[_12] = 0.0f; + out.m[_13] = 0.0f; + out.m[_14] = -((right + left) / (right - left)); + + out.m[_21] = 0.0f; + out.m[_22] = 2.0f / (top - bottom); + out.m[_23] = 0.0f; + out.m[_24] = -((top + bottom) / (top - bottom)); + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = -2.0f / (far_ - near_); + out.m[_34] = -((far_ + near_) / (far_ - near_)); + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a perspective projection matrix. This is equivalent to a + * matrix created by using OpenGL's glFrustum() function. + * @param left coordinate of the left vertical clipping plane + * @param right coordinate of the right vertical clipping plane + * @param bottom coordinate of the bottom horizontal clipping plane + * @param top coordinate of the top horizontal clipping plane + * @param near near clipping plane distance + * @param far far clipping plane distance + * @return a perspective projection matrix + */ +inline Matrix4x4 Matrix4x4::CreatePerspective(float left, float right, float bottom, float top, float near_, float far_) +{ + Matrix4x4 out; + + out.m[_11] = (2.0f * near_) / (right - left); + out.m[_12] = 0.0f; + out.m[_13] = (right + left) / (right - left); + out.m[_14] = 0.0f; + + out.m[_21] = 0.0f; + out.m[_22] = (2.0f * near_) / (top - bottom); + out.m[_23] = (top + bottom) / (top - bottom); + out.m[_24] = 0.0f; + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = -((far_ + near_)) / (far_ - near_); + out.m[_34] = -((2.0f * far_ * near_)) / (far_ - near_); + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = -1.0f; + out.m[_44] = 0.0f; + + return out; +} + +/** + * Constructs a perspective projection matrix. This is equivalent to a + * matrix created by using OpenGL's gluPerspective() function. + * @param fieldOfView the field of view in the y direction (specified in radians) + * @param aspectRatio the aspect ratio of the viewport + * @param near near clipping plane distance + * @param far far clipping plane distance + * @return a perspective projection matrix + */ +inline Matrix4x4 Matrix4x4::CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float near_, float far_) +{ + Matrix4x4 out; + + float f = 1.0f / tanf(fieldOfView / 2.0f); + + out.m[_11] = f / aspectRatio; + out.m[_12] = 0.0f; + out.m[_13] = 0.0f; + out.m[_14] = 0.0f; + + out.m[_21] = 0.0f; + out.m[_22] = f; + out.m[_23] = 0.0f; + out.m[_24] = 0.0f; + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = (far_ + near_) / (near_ - far_); + out.m[_34] = (2.0f * far_ * near_) / (near_ - far_); + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = -1.0f; + out.m[_44] = 0.0f; + + return out; +} + +/** + * Sets up a rotation matrix about the specified axis. This returns a matrix + * equivalent to the matrix that OpenGL multiples into the modelview matrix + * whenever glRotate(angle, axis.x, axis.y, axis.z) is called. + * @param angle angle in radians to rotate + * @param axis unit vector denoting the axis for the rotation + * @return a rotation matrix representing the specific axis rotation + */ +inline Matrix4x4 Matrix4x4::CreateRotation(float angle, const Vector3 &axis) +{ + Matrix4x4 out; + + float s = sinf(angle); + float c = cosf(angle); + + out.m[_11] = (axis.x * axis.x) * (1.0f - c) + c; + out.m[_12] = (axis.x * axis.y) * (1.0f - c) - (axis.z * s); + out.m[_13] = (axis.x * axis.z) * (1.0f - c) + (axis.y * s); + out.m[_14] = 0.0f; + + out.m[_21] = (axis.y * axis.x) * (1.0f - c) + (axis.z * s); + out.m[_22] = (axis.y * axis.y) * (1.0f - c) + c; + out.m[_23] = (axis.y * axis.z) * (1.0f - c) - (axis.x * s); + out.m[_24] = 0.0f; + + out.m[_31] = (axis.z * axis.x) * (1.0f - c) - (axis.y * s); + out.m[_32] = (axis.z * axis.y) * (1.0f - c) + (axis.x * s); + out.m[_33] = (axis.z * axis.z) * (1.0f - c) + c; + out.m[_34] = 0.0f; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a rotation matrix for a rotation around the x axis. This returns + * a matrix equivalent to the matrix that OpenGL multiples into the modelview + * matrix whenever glRotate(angle, 1.0f, 0.0f, 0.0f) is called. + * @param angle angle to rotate the x axis around (in radians) + * @return the rotation matrix + */ +inline Matrix4x4 Matrix4x4::CreateRotationX(float angle) +{ + Matrix4x4 out; + + float s = sinf(angle); + float c = cosf(angle); + + out.m[_11] = 1.0f; + out.m[_12] = 0.0f; + out.m[_13] = 0.0f; + out.m[_14] = 0.0f; + + out.m[_21] = 0.0f; + out.m[_22] = c; + out.m[_23] = -s; + out.m[_24] = 0.0f; + + out.m[_31] = 0.0f; + out.m[_32] = s; + out.m[_33] = c; + out.m[_34] = 0.0f; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a rotation matrix for a rotation around the y axis. This returns + * a matrix equivalent to the matrix that OpenGL multiples into the modelview + * matrix whenever glRotate(angle, 0.0f, 1.0f, 0.0f) is called. + * @param angle angle to rotate the y axis around (in radians) + * @return the rotation matrix + */ +inline Matrix4x4 Matrix4x4::CreateRotationY(float angle) +{ + Matrix4x4 out; + + float s = sinf(angle); + float c = cosf(angle); + + out.m[_11] = c; + out.m[_12] = 0.0f; + out.m[_13] = s; + out.m[_14] = 0.0f; + + out.m[_21] = 0.0f; + out.m[_22] = 1.0f; + out.m[_23] = 0.0f; + out.m[_24] = 0.0f; + + out.m[_31] = -s; + out.m[_32] = 0.0f; + out.m[_33] = c; + out.m[_34] = 0.0f; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a rotation matrix for a rotation around the z axis. This returns + * a matrix equivalent to the matrix that OpenGL multiples into the modelview + * matrix whenever glRotate(angle, 0.0f, 0.0f, 1.0f) is called. + * @param angle angle to rotate the z axis around (in radians) + * @return the rotation matrix + */ +inline Matrix4x4 Matrix4x4::CreateRotationZ(float angle) +{ + Matrix4x4 out; + + float s = sinf(angle); + float c = cosf(angle); + + out.m[_11] = c; + out.m[_12] = -s; + out.m[_13] = 0.0f; + out.m[_14] = 0.0f; + + out.m[_21] = s; + out.m[_22] = c; + out.m[_23] = 0.0f; + out.m[_24] = 0.0f; + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = 1.0f; + out.m[_34] = 0.0f; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a scaling matrix from scaling factors for each axis. This returns + * a matrix equivalent to the matrix that OpenGL multiples into the modelview + * matrix whenever glScale(x, y, z) is called. + * @param x the scale factor for the x axis + * @param y the scale factor for the y axis + * @param z the scale factor for the z axis + * @return a scaling matrix + */ +inline Matrix4x4 Matrix4x4::CreateScale(float x, float y, float z) +{ + Matrix4x4 out; + + out.m[_11] = x; + out.m[_12] = 0.0f; + out.m[_13] = 0.0f; + out.m[_14] = 0.0f; + + out.m[_21] = 0.0f; + out.m[_22] = y; + out.m[_23] = 0.0f; + out.m[_24] = 0.0f; + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = z; + out.m[_34] = 0.0f; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a translation matrix. This returns a matrix equivalent to the + * matrix that OpenGL multiples into the modelview matrix whenever + * glTranslate(x, y, z) is called. + * @param x the amount to translate on the x axis + * @param y the amount to translate on the y axis + * @param z the amount to translate on the z axis + * @return a translation matrix + */ +inline Matrix4x4 Matrix4x4::CreateTranslation(float x, float y, float z) +{ + Matrix4x4 out; + + out.m[_11] = 1.0f; + out.m[_12] = 0.0f; + out.m[_13] = 0.0f; + out.m[_14] = x; + + out.m[_21] = 0.0f; + out.m[_22] = 1.0f; + out.m[_23] = 0.0f; + out.m[_24] = y; + + out.m[_31] = 0.0f; + out.m[_32] = 0.0f; + out.m[_33] = 1.0f; + out.m[_34] = z; + + out.m[_41] = 0.0f; + out.m[_42] = 0.0f; + out.m[_43] = 0.0f; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Constructs a world matrix. + * @param position the position of the object (translation) + * @param forward the forward facing direction of the object + * @param up the up direction of the object + * @return a world matrix + */ +inline Matrix4x4 Matrix4x4::CreateWorld(const Vector3 &position, const Vector3 &forward, const Vector3 &up) +{ + Matrix4x4 out; + + Vector3 f = Vector3::Normalize(-forward); + Vector3 l = Vector3::Normalize(Vector3::Cross(up, f)); + Vector3 u = Vector3::Cross(f, l); + + out.m[_11] = l.x; + out.m[_21] = l.y; + out.m[_31] = l.z; + out.m[_41] = 0.0f; + + out.m[_12] = u.x; + out.m[_22] = u.y; + out.m[_32] = u.z; + out.m[_42] = 0.0f; + + out.m[_13] = f.x; + out.m[_23] = f.y; + out.m[_33] = f.z; + out.m[_43] = 0.0f; + + out.m[_14] = position.x; + out.m[_24] = position.y; + out.m[_34] = position.z; + out.m[_44] = 1.0f; + + return out; +} + +/** + * Calculates the inverse of the specified matrix. + * @param m the matrix to calculate the inverse of + * @return the inverse of the specified matrix + */ +inline Matrix4x4 Matrix4x4::Inverse(const Matrix4x4 &m) +{ + float d = m.GetDeterminant(); + if (IS_CLOSE_ENOUGH(d, 0.0f)) + return IDENTITY_MATRIX; + else + { + Matrix4x4 out; + + d = 1.0f / d; + + out.m[_11] = d * (m.m[_22] * (m.m[_33] * m.m[_44] - m.m[_43] * m.m[_34]) + m.m[_32] * (m.m[_43] * m.m[_24] - m.m[_23] * m.m[_44]) + m.m[_42] * (m.m[_23] * m.m[_34] - m.m[_33] * m.m[_24])); + out.m[_21] = d * (m.m[_23] * (m.m[_31] * m.m[_44] - m.m[_41] * m.m[_34]) + m.m[_33] * (m.m[_41] * m.m[_24] - m.m[_21] * m.m[_44]) + m.m[_43] * (m.m[_21] * m.m[_34] - m.m[_31] * m.m[_24])); + out.m[_31] = d * (m.m[_24] * (m.m[_31] * m.m[_42] - m.m[_41] * m.m[_32]) + m.m[_34] * (m.m[_41] * m.m[_22] - m.m[_21] * m.m[_42]) + m.m[_44] * (m.m[_21] * m.m[_32] - m.m[_31] * m.m[_22])); + out.m[_41] = d * (m.m[_21] * (m.m[_42] * m.m[_33] - m.m[_32] * m.m[_43]) + m.m[_31] * (m.m[_22] * m.m[_43] - m.m[_42] * m.m[_23]) + m.m[_41] * (m.m[_32] * m.m[_23] - m.m[_22] * m.m[_33])); + + out.m[_12] = d * (m.m[_32] * (m.m[_13] * m.m[_44] - m.m[_43] * m.m[_14]) + m.m[_42] * (m.m[_33] * m.m[_14] - m.m[_13] * m.m[_34]) + m.m[_12] * (m.m[_43] * m.m[_34] - m.m[_33] * m.m[_44])); + out.m[_22] = d * (m.m[_33] * (m.m[_11] * m.m[_44] - m.m[_41] * m.m[_14]) + m.m[_43] * (m.m[_31] * m.m[_14] - m.m[_11] * m.m[_34]) + m.m[_13] * (m.m[_41] * m.m[_34] - m.m[_31] * m.m[_44])); + out.m[_32] = d * (m.m[_34] * (m.m[_11] * m.m[_42] - m.m[_41] * m.m[_12]) + m.m[_44] * (m.m[_31] * m.m[_12] - m.m[_11] * m.m[_32]) + m.m[_14] * (m.m[_41] * m.m[_32] - m.m[_31] * m.m[_42])); + out.m[_42] = d * (m.m[_31] * (m.m[_42] * m.m[_13] - m.m[_12] * m.m[_43]) + m.m[_41] * (m.m[_12] * m.m[_33] - m.m[_32] * m.m[_13]) + m.m[_11] * (m.m[_32] * m.m[_43] - m.m[_42] * m.m[_33])); + + out.m[_13] = d * (m.m[_42] * (m.m[_13] * m.m[_24] - m.m[_23] * m.m[_14]) + m.m[_12] * (m.m[_23] * m.m[_44] - m.m[_43] * m.m[_24]) + m.m[_22] * (m.m[_43] * m.m[_14] - m.m[_13] * m.m[_44])); + out.m[_23] = d * (m.m[_43] * (m.m[_11] * m.m[_24] - m.m[_21] * m.m[_14]) + m.m[_13] * (m.m[_21] * m.m[_44] - m.m[_41] * m.m[_24]) + m.m[_23] * (m.m[_41] * m.m[_14] - m.m[_11] * m.m[_44])); + out.m[_33] = d * (m.m[_44] * (m.m[_11] * m.m[_22] - m.m[_21] * m.m[_12]) + m.m[_14] * (m.m[_21] * m.m[_42] - m.m[_41] * m.m[_22]) + m.m[_24] * (m.m[_41] * m.m[_12] - m.m[_11] * m.m[_42])); + out.m[_43] = d * (m.m[_41] * (m.m[_22] * m.m[_13] - m.m[_12] * m.m[_23]) + m.m[_11] * (m.m[_42] * m.m[_23] - m.m[_22] * m.m[_43]) + m.m[_21] * (m.m[_12] * m.m[_43] - m.m[_42] * m.m[_13])); + + out.m[_14] = d * (m.m[_12] * (m.m[_33] * m.m[_24] - m.m[_23] * m.m[_34]) + m.m[_22] * (m.m[_13] * m.m[_34] - m.m[_33] * m.m[_14]) + m.m[_32] * (m.m[_23] * m.m[_14] - m.m[_13] * m.m[_24])); + out.m[_24] = d * (m.m[_13] * (m.m[_31] * m.m[_24] - m.m[_21] * m.m[_34]) + m.m[_23] * (m.m[_11] * m.m[_34] - m.m[_31] * m.m[_14]) + m.m[_33] * (m.m[_21] * m.m[_14] - m.m[_11] * m.m[_24])); + out.m[_34] = d * (m.m[_14] * (m.m[_31] * m.m[_22] - m.m[_21] * m.m[_32]) + m.m[_24] * (m.m[_11] * m.m[_32] - m.m[_31] * m.m[_12]) + m.m[_34] * (m.m[_21] * m.m[_12] - m.m[_11] * m.m[_22])); + out.m[_44] = d * (m.m[_11] * (m.m[_22] * m.m[_33] - m.m[_32] * m.m[_23]) + m.m[_21] * (m.m[_32] * m.m[_13] - m.m[_12] * m.m[_33]) + m.m[_31] * (m.m[_12] * m.m[_23] - m.m[_22] * m.m[_13])); + + return out; + } +} + +/** + * Calculates the transpose of a given matrix. + * @param m the matrix to get the transpose of + * @return the transpose matrix + */ +inline Matrix4x4 Matrix4x4::Transpose(const Matrix4x4 &m) +{ + Matrix4x4 out; + + out.m[_11] = m.m[_11]; + out.m[_12] = m.m[_21]; + out.m[_13] = m.m[_31]; + out.m[_14] = m.m[_41]; + + out.m[_21] = m.m[_12]; + out.m[_22] = m.m[_22]; + out.m[_23] = m.m[_32]; + out.m[_24] = m.m[_42]; + + out.m[_31] = m.m[_13]; + out.m[_32] = m.m[_23]; + out.m[_33] = m.m[_33]; + out.m[_34] = m.m[_43]; + + out.m[_41] = m.m[_14]; + out.m[_42] = m.m[_24]; + out.m[_43] = m.m[_34]; + out.m[_44] = m.m[_44]; + + return out; +} + +inline Matrix4x4 operator+(const Matrix4x4 &left, const Matrix4x4 &right) +{ + Matrix4x4 result; + + result.m[_11] = left.m[_11] + right.m[_11]; + result.m[_12] = left.m[_12] + right.m[_12]; + result.m[_13] = left.m[_13] + right.m[_13]; + result.m[_14] = left.m[_14] + right.m[_14]; + result.m[_21] = left.m[_21] + right.m[_21]; + result.m[_22] = left.m[_22] + right.m[_22]; + result.m[_23] = left.m[_23] + right.m[_23]; + result.m[_24] = left.m[_24] + right.m[_24]; + result.m[_31] = left.m[_31] + right.m[_31]; + result.m[_32] = left.m[_32] + right.m[_32]; + result.m[_33] = left.m[_33] + right.m[_33]; + result.m[_34] = left.m[_34] + right.m[_34]; + result.m[_41] = left.m[_41] + right.m[_41]; + result.m[_42] = left.m[_42] + right.m[_42]; + result.m[_43] = left.m[_43] + right.m[_43]; + result.m[_44] = left.m[_44] + right.m[_44]; + + return result; +} + +inline Matrix4x4 &operator+=(Matrix4x4 &left, const Matrix4x4 &right) +{ + left = left + right; + return left; +} + +inline Matrix4x4 operator-(const Matrix4x4 &left, const Matrix4x4 &right) +{ + Matrix4x4 result; + + result.m[_11] = left.m[_11] - right.m[_11]; + result.m[_12] = left.m[_12] - right.m[_12]; + result.m[_13] = left.m[_13] - right.m[_13]; + result.m[_14] = left.m[_14] - right.m[_14]; + result.m[_21] = left.m[_21] - right.m[_21]; + result.m[_22] = left.m[_22] - right.m[_22]; + result.m[_23] = left.m[_23] - right.m[_23]; + result.m[_24] = left.m[_24] - right.m[_24]; + result.m[_31] = left.m[_31] - right.m[_31]; + result.m[_32] = left.m[_32] - right.m[_32]; + result.m[_33] = left.m[_33] - right.m[_33]; + result.m[_34] = left.m[_34] - right.m[_34]; + result.m[_41] = left.m[_41] - right.m[_41]; + result.m[_42] = left.m[_42] - right.m[_42]; + result.m[_43] = left.m[_43] - right.m[_43]; + result.m[_44] = left.m[_44] - right.m[_44]; + + return result; +} + +inline Matrix4x4 &operator-=(Matrix4x4 &left, const Matrix4x4 &right) +{ + left = left - right; + return left; +} + +inline Matrix4x4 operator*(const Matrix4x4 &left, const Matrix4x4 &right) +{ + Matrix4x4 result; + + result.m[_11] = left.m[_11] * right.m[_11] + left.m[_12] * right.m[_21] + left.m[_13] * right.m[_31] + left.m[_14] * right.m[_41]; + result.m[_12] = left.m[_11] * right.m[_12] + left.m[_12] * right.m[_22] + left.m[_13] * right.m[_32] + left.m[_14] * right.m[_42]; + result.m[_13] = left.m[_11] * right.m[_13] + left.m[_12] * right.m[_23] + left.m[_13] * right.m[_33] + left.m[_14] * right.m[_43]; + result.m[_14] = left.m[_11] * right.m[_14] + left.m[_12] * right.m[_24] + left.m[_13] * right.m[_34] + left.m[_14] * right.m[_44]; + + result.m[_21] = left.m[_21] * right.m[_11] + left.m[_22] * right.m[_21] + left.m[_23] * right.m[_31] + left.m[_24] * right.m[_41]; + result.m[_22] = left.m[_21] * right.m[_12] + left.m[_22] * right.m[_22] + left.m[_23] * right.m[_32] + left.m[_24] * right.m[_42]; + result.m[_23] = left.m[_21] * right.m[_13] + left.m[_22] * right.m[_23] + left.m[_23] * right.m[_33] + left.m[_24] * right.m[_43]; + result.m[_24] = left.m[_21] * right.m[_14] + left.m[_22] * right.m[_24] + left.m[_23] * right.m[_34] + left.m[_24] * right.m[_44]; + + result.m[_31] = left.m[_31] * right.m[_11] + left.m[_32] * right.m[_21] + left.m[_33] * right.m[_31] + left.m[_34] * right.m[_41]; + result.m[_32] = left.m[_31] * right.m[_12] + left.m[_32] * right.m[_22] + left.m[_33] * right.m[_32] + left.m[_34] * right.m[_42]; + result.m[_33] = left.m[_31] * right.m[_13] + left.m[_32] * right.m[_23] + left.m[_33] * right.m[_33] + left.m[_34] * right.m[_43]; + result.m[_34] = left.m[_31] * right.m[_14] + left.m[_32] * right.m[_24] + left.m[_33] * right.m[_34] + left.m[_34] * right.m[_44]; + + result.m[_41] = left.m[_41] * right.m[_11] + left.m[_42] * right.m[_21] + left.m[_43] * right.m[_31] + left.m[_44] * right.m[_41]; + result.m[_42] = left.m[_41] * right.m[_12] + left.m[_42] * right.m[_22] + left.m[_43] * right.m[_32] + left.m[_44] * right.m[_42]; + result.m[_43] = left.m[_41] * right.m[_13] + left.m[_42] * right.m[_23] + left.m[_43] * right.m[_33] + left.m[_44] * right.m[_43]; + result.m[_44] = left.m[_41] * right.m[_14] + left.m[_42] * right.m[_24] + left.m[_43] * right.m[_34] + left.m[_44] * right.m[_44]; + + return result; +} + +inline Matrix4x4 &operator*=(Matrix4x4 &left, const Matrix4x4 &right) +{ + left = left * right; + return left; +} + +inline Matrix4x4 operator*(const Matrix4x4 &left, float right) +{ + Matrix4x4 result; + + result.m[_11] = left.m[_11] * right; + result.m[_12] = left.m[_12] * right; + result.m[_13] = left.m[_13] * right; + result.m[_14] = left.m[_14] * right; + result.m[_21] = left.m[_21] * right; + result.m[_22] = left.m[_22] * right; + result.m[_23] = left.m[_23] * right; + result.m[_24] = left.m[_24] * right; + result.m[_31] = left.m[_31] * right; + result.m[_32] = left.m[_32] * right; + result.m[_33] = left.m[_33] * right; + result.m[_34] = left.m[_34] * right; + result.m[_41] = left.m[_41] * right; + result.m[_42] = left.m[_42] * right; + result.m[_43] = left.m[_43] * right; + result.m[_44] = left.m[_44] * right; + + return result; +} + +inline Matrix4x4 &operator*=(Matrix4x4 &left, float right) +{ + left = left * right; + return left; +} + +inline Vector3 operator*(const Vector3 &left, const Matrix4x4 &right) +{ + return Vector3( + left.x * right.m[_11] + left.y * right.m[_12] + left.z * right.m[_13] + right.m[_14], + left.x * right.m[_21] + left.y * right.m[_22] + left.z * right.m[_23] + right.m[_24], + left.x * right.m[_31] + left.y * right.m[_32] + left.z * right.m[_33] + right.m[_34] + ); +} + +#endif diff --git a/MeshConverter/src/geometry/quaternion.h b/MeshConverter/src/geometry/quaternion.h new file mode 100644 index 0000000..0db783c --- /dev/null +++ b/MeshConverter/src/geometry/quaternion.h @@ -0,0 +1,491 @@ +#ifndef __GEOMETRY_QUATERNION_H_INCLUDED__ +#define __GEOMETRY_QUATERNION_H_INCLUDED__ + +#include +#include "common.h" +#include "vector3.h" +#include "matrix4x4.h" + +/** + * Represents a quaternion to store an orientation or angular + * displacement and provides methods for conversion/manipulation + *

Referenced/based on code from:

+ *
    + *
  • 3D Math Primer for Graphics and Game Development (Dunn & Parberry, 2002)
  • + *
  • More OpenGL Game Programming (Dave Astle, 2006)
  • + *
  • http://www.dhpoware.com/source/mathlib.html
  • + *
+ * @author Gered + */ +class Quaternion +{ +public: + Quaternion() {} + + Quaternion(float w, float x, float y, float z) + { + this->w = w; + this->x = x; + this->y = y; + this->z = z; + } + + Quaternion(float w, const Vector3 &v) + { + this->w = w; + this->x = v.x; + this->y = v.y; + this->z = v.z; + } + + Quaternion(const float *q) + { + w = q[0]; + x = q[1]; + y = q[2]; + z = q[3]; + } + + ~Quaternion() {} + + void Set(float w, float x, float y, float z); + Matrix4x4 ToMatrix() const; + Vector3 GetVector() const; + + static Quaternion Cross(const Quaternion &a, const Quaternion &b); + static float Dot(const Quaternion &a, const Quaternion &b); + static float Length(const Quaternion &q); + static float LengthSquared(const Quaternion &q); + static Quaternion Normalize(const Quaternion &q); + static Quaternion Conjugate(const Quaternion &q); + static Quaternion Inverse(const Quaternion &q); + static Quaternion CreateFromEulerAngles(float x, float y, float z); + static Quaternion CreateFromAxisAngle(float angle, const Vector3 &axis); + static Quaternion CreateFromRotationMatrix(const Matrix4x4 &matrix); + static void ExtractAxisAngle(const Quaternion &q, float *angle, Vector3 *axis); + static Quaternion Lerp(const Quaternion &a, const Quaternion &b, float interpolation); + static Quaternion Slerp(const Quaternion &a, const Quaternion &b, float interpolation); + + float w; + float x; + float y; + float z; +}; + +Quaternion operator+(const Quaternion &left, const Quaternion &right); +Quaternion &operator+=(Quaternion &left, const Quaternion &right); +Quaternion operator-(const Quaternion &left, const Quaternion &right); +Quaternion &operator-=(Quaternion &left, const Quaternion &right); +Quaternion operator*(const Quaternion &left, float right); +Quaternion &operator*=(Quaternion &left, float right); +Quaternion operator*(const Quaternion &left, const Quaternion &right); +Quaternion &operator*=(Quaternion &left, const Quaternion &right); +Quaternion operator/(const Quaternion &left, float right); +Quaternion &operator/=(Quaternion &left, float right); +Vector3 operator*(const Vector3 &left, const Quaternion &right); + +#define IDENTITY_QUATERNION Quaternion(1.0f, 0.0f, 0.0f, 0.0f) + +inline void Quaternion::Set(float w, float x, float y, float z) +{ + this->w = w; + this->x = x; + this->y = y; + this->z = z; +} + +/** + * Converts a quaternion to a rotation matrix + * @return Matrix4x4 + */ +inline Matrix4x4 Quaternion::ToMatrix() const +{ + Matrix4x4 output; + + output.m[_11] = 1.0f - (2.0f * ((y * y) + (z * z))); + output.m[_21] = 2.0f * ((x * y) + (z * w)); + output.m[_31] = 2.0f * ((z * x) - (y * w)); + output.m[_41] = 0.0f; + + output.m[_12] = 2.0f * ((x * y) - (z * w)); + output.m[_22] = 1.0f - (2.0f * ((z * z) + (x * x))); + output.m[_32] = 2.0f * ((y * z) + (x * w)); + output.m[_42] = 0.0f; + + output.m[_13] = 2.0f * ((z * x) + (y * w)); + output.m[_23] = 2.0f * ((y * z) - (x * w)); + output.m[_33] = 1.0f - (2.0f * ((y * y) + (x * x))); + output.m[_43] = 0.0f; + + output.m[_14] = 0.0f; + output.m[_24] = 0.0f; + output.m[_34] = 0.0f; + output.m[_44] = 1.0f; + + return output; +} + +/** + * @return Vector3 the vector component of the quaternion. + */ +inline Vector3 Quaternion::GetVector() const +{ + return Vector3(x, y, z); +} + +/** + * Computes the cross product of two quaternions + * @param a first quaternion + * @param b second quaternion + * @return Quaternion the cross product + */ +inline Quaternion Quaternion::Cross(const Quaternion &a, const Quaternion &b) +{ + return a * b; +} + +/** + * Computes the dot product of 2 quaternions. + * @param a first quaternion + * @param b second quaternion + * @return float the dot product + */ +inline float Quaternion::Dot(const Quaternion &a, const Quaternion &b) +{ + return (a.w * b.w) + (a.x * b.x) + (a.y * b.y) + (a.z * b.z); +} + +/** + * Computes the length (magnitude) of a quaternion. + * @param q quaternion to retrieve the length of + * @return float the length + */ +inline float Quaternion::Length(const Quaternion &q) +{ + return sqrtf((q.w * q.w) + (q.x * q.x) + (q.y * q.y) + (q.z * q.z)); +} + +/** + * Computes the squared length of a quaternion (the length minus the + * sqrt call). + * @param q quaternion to retrieve the squared length of + * @return float the squared length + */ +inline float Quaternion::LengthSquared(const Quaternion &q) +{ + return (q.w * q.w) + (q.x * q.x) + (q.y * q.y) + (q.z * q.z); +} + +/** + * Normalizes a quaternion (only if necessary) + * @param q quaternion to be normalized + * @return Quaternion normalized quaternion + */ +inline Quaternion Quaternion::Normalize(const Quaternion &q) +{ + float inverseLength = 1.0f / Length(q); + return Quaternion( + q.w * inverseLength, + q.x * inverseLength, + q.y * inverseLength, + q.z * inverseLength + ); +} + +/** + * Computes the conjugate of a quaternion. If the quaternion + * is unit length, this also returns the inverse. + * @param q quaternion to retrieve the conjugate of + * @return Quaternion conjugate + */ +inline Quaternion Quaternion::Conjugate(const Quaternion &q) +{ + return Quaternion(q.w, -q.x, -q.y, -q.z); +} + +/** + * Computes the inverse of a given quaternion + * @param q quaternion to retrieve the inverse of + * @return Quaternion inverse of the quaternion + */ +inline Quaternion Quaternion::Inverse(const Quaternion &q) +{ + float inverseSquaredLength = 1.0f / LengthSquared(q); + return Quaternion( + q.w * inverseSquaredLength, + -q.x * inverseSquaredLength, + -q.y * inverseSquaredLength, + -q.z * inverseSquaredLength + ); +} + +/** + * Converts euler angles to a quaternion + * @param x x angle of rotation (specified in radians) + * @param y y angle of rotation (specified in radians) + * @param z z angle of rotation (specified in radians) + * @return Quaternion quaternion equivalent to the euler angle + * orientation + */ +inline Quaternion Quaternion::CreateFromEulerAngles(float x, float y, float z) +{ + Quaternion qx(cosf(x / 2.0f), sinf(x / 2.0f), 0.0f, 0.0f); + Quaternion qy(cosf(y / 2.0f), 0.0f, sinf(y / 2.0f), 0.0f); + Quaternion qz(cosf(z / 2.0f), 0.0f, 0.0f, sinf(z / 2.0f)); + + return Normalize(qz * qy * qx); +} + +/** + * Converts an axis angle to a quaternion + * @param angle the angle to rotate be (specified in radians) + * @param axis the axis being rotated about + * @return Quaternion quaternion equivalent to the axis angle + * orientation + */ +inline Quaternion Quaternion::CreateFromAxisAngle(float angle, const Vector3 &axis) +{ + Quaternion result; + + float c = cosf(angle / 2.0f); + float s = sinf(angle / 2.0f); + + result.w = c; + result.x = axis.x * s; + result.y = axis.y * s; + result.z = axis.z * s; + + return Normalize(result); +} + +/** + * Converts a rotation matrix to a quaternion + * @param matrix matrix to be converted + * @return Quaternion quaternion equivalent of the rotation + * matrix + */ +inline Quaternion Quaternion::CreateFromRotationMatrix(const Matrix4x4 &matrix) +{ + Quaternion result; + + float n = matrix.m[_11] + matrix.m[_22] + matrix.m[_33]; + if (n > 0.0f) + { + float a = sqrtf(n + 1.0f); + result.w = a / 2.0f; + a = 0.5f / a; + result.x = (matrix.m[_32] - matrix.m[_23]) * a; + result.y = (matrix.m[_13] - matrix.m[_31]) * a; + result.z = (matrix.m[_21] - matrix.m[_12]) * a; + } + else if ((matrix.m[_11] >= matrix.m[_22]) && (matrix.m[_11] >= matrix.m[_33])) + { + float a = sqrtf(1.0f + matrix.m[_11] - matrix.m[_22] - matrix.m[_33]); + float b = 0.5f / a; + + result.x = 0.5f * a; + result.y = (matrix.m[_21] + matrix.m[_12]) * b; + result.z = (matrix.m[_31] + matrix.m[_13]) * b; + result.w = (matrix.m[_32] - matrix.m[_23]) * b; + } + else if (matrix.m[_22] > matrix.m[_33]) + { + float a = sqrtf(1.0f + matrix.m[_22] - matrix.m[_11] - matrix.m[_33]); + float b = 0.5f / a; + + result.x = (matrix.m[_12] + matrix.m[_21]) * b; + result.y = 0.5f * a; + result.z = (matrix.m[_23] + matrix.m[_32]) * b; + result.w = (matrix.m[_13] - matrix.m[_31]) * b; + } + else + { + float a = sqrtf(1.0f + matrix.m[_33] - matrix.m[_11] - matrix.m[_22]); + float b = 0.5f / a; + + result.x = (matrix.m[_13] + matrix.m[_31]) * b; + result.y = (matrix.m[_23] + matrix.m[_32]) * b; + result.z = 0.5f * a; + result.w = (matrix.m[_21] - matrix.m[_12]) * b; + } + + return Normalize(result); +} + +/** + * Converts a quaternion to an axis-angle representation. + * @param q the normalized quaternion to convert + * @param angle the angle (in radians) + * @param axis a vector that will contain the axis + */ +inline void Quaternion::ExtractAxisAngle(const Quaternion &q, float *angle, Vector3 *axis) +{ + *angle = 2.0f * acosf(q.w); + float n = sqrtf(1.0f - (q.w * q.w)); + if (n > 0.0001f) + *axis = q.GetVector() / n; + else + *axis = X_AXIS; +} + +/** + * Linearly interpolates between two quaternions. + * @param a the first quaternion + * @param b the second quaternion + * @param interpolation the amount to interpolate + * @return Quaternion the interpolated quaternion + */ +inline Quaternion Quaternion::Lerp(const Quaternion &a, const Quaternion &b, float interpolation) +{ + return (a * (1.0f - interpolation)) + (b * interpolation); +} + +/** + * Interpolates between two quaternions using spherical + * interpolation. + * @param a the first quaternion + * @param b the second quaternion + * @param interpolation the amount to interpolate + * @return Quaternion the interpolated quaternion + */ +inline Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float interpolation) +{ + if (LengthSquared(a) == 0.0f) + { + if (LengthSquared(b) == 0.0f) + return IDENTITY_QUATERNION; + else + return b; + } + else if (LengthSquared(b) == 0.0f) + return a; + + Quaternion q1 = a; + Quaternion q2 = b; + + float cosHalfAngle = q1.w * q2.w + Vector3::Dot(q1.GetVector(), q2.GetVector()); + + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) + return q1; + else if (cosHalfAngle < 0.0f) + { + q2.x = -q2.x; + q2.y = -q2.y; + q2.z = -q2.z; + q2.w = -q2.w; + cosHalfAngle = -cosHalfAngle; + } + + float blendA; + float blendB; + if (cosHalfAngle < 0.99f) + { + float halfAngle = acosf(cosHalfAngle); + float sinHalfAngle = sinf(halfAngle); + float oneOverSinHalfAngle = 1.0f / sinHalfAngle; + blendA = sinf(halfAngle * (1.0f - interpolation)) * oneOverSinHalfAngle; + blendB = sinf(halfAngle * interpolation) * oneOverSinHalfAngle; + } + else + { + blendA = 1.0f - interpolation; + blendB = interpolation; + } + + Quaternion result(q1.w * blendA + q2.w * blendB, q1.GetVector() * blendA + q2.GetVector() * blendB); + if (LengthSquared(result) > 0.0f) + return Normalize(result); + else + return IDENTITY_QUATERNION; +} + +inline Quaternion operator+(const Quaternion &left, const Quaternion &right) +{ + return Quaternion( + left.w + right.w, + left.x + right.x, + left.y + right.y, + left.z + right.z + ); +} + +inline Quaternion &operator+=(Quaternion &left, const Quaternion &right) +{ + left = left + right; + return left; +} + +inline Quaternion operator-(const Quaternion &left, const Quaternion &right) +{ + return Quaternion( + left.w - right.w, + left.x - right.x, + left.y - right.y, + left.z - right.z + ); +} + +inline Quaternion &operator-=(Quaternion &left, const Quaternion &right) +{ + left = left - right; + return left; +} + +inline Quaternion operator*(const Quaternion &left, float right) +{ + return Quaternion( + left.w * right, + left.x * right, + left.y * right, + left.z * right + ); +} + +inline Quaternion &operator*=(Quaternion &left, float right) +{ + left = left * right; + return left; +} + +inline Quaternion operator*(const Quaternion &left, const Quaternion &right) +{ + return Quaternion( + (left.w * right.w) - (left.x * right.x) - (left.y * right.y) - (left.z * right.z), + (left.w * right.x) + (left.x * right.w) + (left.y * right.z) - (left.z * right.y), + (left.w * right.y) + (left.y * right.w) + (left.z * right.x) - (left.x * right.z), + (left.w * right.z) + (left.z * right.w) + (left.x * right.y) - (left.y * right.x) + ); +} + +inline Quaternion &operator*=(Quaternion &left, const Quaternion &right) +{ + left = left * right; + return left; +} + +inline Quaternion operator/(const Quaternion &left, float right) +{ + return Quaternion( + left.w / right, + left.x / right, + left.y / right, + left.z / right + ); +} + +inline Quaternion &operator/=(Quaternion &left, float right) +{ + left = left / right; + return left; +} + +inline Vector3 operator*(const Vector3 &left, const Quaternion &right) +{ + return Vector3( + ((left.x * ((1.0f - (right.y * (right.y + right.y))) - (right.z * (right.z + right.z)))) + (left.y * ((right.x * (right.y + right.y)) - (right.w * (right.z + right.z))))) + (left.z * ((right.x * (right.z + right.z)) + (right.w * (right.y + right.y)))), + ((left.x * ((right.x * (right.y + right.y)) + (right.w * (right.z + right.z)))) + (left.y * ((1.0f - (right.x * (right.x + right.x))) - (right.z * (right.z + right.z))))) + (left.z * ((right.y * (right.z + right.z)) - (right.w * (right.x + right.x)))), + ((left.x * ((right.x * (right.z + right.z)) - (right.w * (right.y + right.y)))) + (left.y * ((right.y * (right.z + right.z)) + (right.w * (right.x + right.x))))) + (left.z * ((1.0f - (right.x * (right.x + right.x))) - (right.y * (right.y + right.y)))) + ); +} + +#endif diff --git a/MeshConverter/src/geometry/vector2.h b/MeshConverter/src/geometry/vector2.h index 41633e0..596255a 100644 --- a/MeshConverter/src/geometry/vector2.h +++ b/MeshConverter/src/geometry/vector2.h @@ -1,11 +1,236 @@ -#ifndef __VECTOR2_H_INCLUDED__ -#define __VECTOR2_H_INCLUDED__ +#ifndef __GEOMETRY_VECTOR2_H_INCLUDED__ +#define __GEOMETRY_VECTOR2_H_INCLUDED__ +#include + +/** + * Represents a 2D vector and provides common methods for vector math. + *

Referenced/based on code from:

+ *
    + *
  • 3D Math Primer for Graphics and Game Development (Dunn & Parberry, 2002)
  • + *
  • http://www.dhpoware.com/source/mathlib.html
  • + *
+ * @author Gered + */ class Vector2 { public: + Vector2() {} + + Vector2(float x, float y) + { + this->x = x; + this->y = y; + } + + Vector2(const float *v) + { + x = v[0]; + y = v[1]; + } + + ~Vector2() {} + + void Set(float x, float y); + + static float Distance(const Vector2 &a, const Vector2 &b); + static float Dot(const Vector2 &a, const Vector2 &b); + static float Length(const Vector2 &v); + static float LengthSquared(const Vector2 &v); + static Vector2 Normalize(const Vector2 &v); + static Vector2 SetLength(const Vector2 &v, float length); + float x; float y; }; -#endif \ No newline at end of file +bool operator==(const Vector2 &left, const Vector2 &right); +Vector2 operator-(const Vector2 &left); +Vector2 operator+(const Vector2 &left, const Vector2 &right); +Vector2 &operator+=(Vector2 &left, const Vector2 &right); +Vector2 operator-(const Vector2 &left, const Vector2 &right); +Vector2 &operator-=(Vector2 &left, const Vector2 &right); +Vector2 operator*(const Vector2 &left, float right); +Vector2 &operator*=(Vector2 &left, float right); +Vector2 operator/(const Vector2 &left, float right); +Vector2 &operator/=(Vector2 &left, float right); +Vector2 operator*(const Vector2 &left, const Vector2 &right); +Vector2 &operator*=(Vector2 &left, const Vector2 &right); +Vector2 operator/(const Vector2 &left, const Vector2 &right); +Vector2 &operator/=(Vector2 &left, const Vector2 &right); + +inline void Vector2::Set(float x, float y) +{ + this->x = x; + this->y = y; +} + +/** + * Calculates the distance between two points. + * @param a the first point + * @param b the second point + * @return the distance between both points + */ +inline float Vector2::Distance(const Vector2 &a, const Vector2 &b) +{ + return sqrtf( + ((b.x - a.x) * (b.x - a.x)) + + ((b.y - a.y) * (b.y - a.y)) + ); +} + +/** + * Computes the dot product of 2 vectors. + * @param a first vector + * @param b second vector + * @return the dot product + */ +inline float Vector2::Dot(const Vector2 &a, const Vector2 &b) +{ + return + (a.x * b.y) + + (a.y * b.y); +} + +/** + * Returns the length (magnitude) of a vector. + * @param v vector to calculate the length of + * @return the vector length + */ +inline float Vector2::Length(const Vector2 &v) +{ + return sqrtf( + (v.x * v.x) + + (v.y * v.y) + ); +} + +/** + * Returns the squared length of a vector (the magnitude minus the sqrt + * call). + * @param v vector to calculate the squared length of + * @return squared length of the vector + */ +inline float Vector2::LengthSquared(const Vector2 &v) +{ + return + (v.x * v.x) + + (v.y * v.y); +} + +/** + * Normalizes a vector. + * @param v vector to normalize + * @return the normalized vector + */ +inline Vector2 Vector2::Normalize(const Vector2 &v) +{ + float inverseLength = 1.0f / Length(v); + return Vector2( + v.x * inverseLength, + v.y * inverseLength + ); +} + +/** + * Adjusts a vector so that it's length is equal to the given length. + * @param v the original vector to be adjusted + * @param length desired vector length (magnitude) + * @return the resulting vector after it's length has been converted to the + * desired amount + */ +inline Vector2 Vector2::SetLength(const Vector2 &v, float length) +{ + return v * (length / Length(v)); +} + +inline bool operator==(const Vector2 &left, const Vector2 &right) +{ + return (left.x == right.x && left.y == right.y); +} + +inline Vector2 operator-(const Vector2 &left) +{ + return Vector2(-left.x, -left.y); +} + +inline Vector2 operator+(const Vector2 &left, const Vector2 &right) +{ + return Vector2(left.x + right.x, left.y + right.y); +} + +inline Vector2 &operator+=(Vector2 &left, const Vector2 &right) +{ + left.x += right.x; + left.y += right.y; + + return left; +} + +inline Vector2 operator-(const Vector2 &left, const Vector2 &right) +{ + return Vector2(left.x - right.x, left.y - right.y); +} + +inline Vector2 &operator-=(Vector2 &left, const Vector2 &right) +{ + left.x -= right.x; + left.y -= right.y; + + return left; +} + +inline Vector2 operator*(const Vector2 &left, float right) +{ + return Vector2(left.x * right, left.y * right); +} + +inline Vector2 &operator*=(Vector2 &left, float right) +{ + left.x *= right; + left.y *= right; + + return left; +} + +inline Vector2 operator/(const Vector2 &left, float right) +{ + return Vector2(left.x / right, left.y / right); +} + +inline Vector2 &operator/=(Vector2 &left, float right) +{ + left.x /= right; + left.y /= right; + + return left; +} + +inline Vector2 operator*(const Vector2 &left, const Vector2 &right) +{ + return Vector2(left.x * right.x, left.y * right.y); +} + +inline Vector2 &operator*=(Vector2 &left, const Vector2 &right) +{ + left.x *= right.x; + left.y *= right.y; + + return left; +} + +inline Vector2 operator/(const Vector2 &left, const Vector2 &right) +{ + return Vector2(left.x / right.x, left.y / right.y); +} + +inline Vector2 &operator/=(Vector2 &left, const Vector2 &right) +{ + left.x /= right.x; + left.y /= right.y; + + return left; +} + + +#endif diff --git a/MeshConverter/src/geometry/vector3.h b/MeshConverter/src/geometry/vector3.h index debac95..1803c8a 100644 --- a/MeshConverter/src/geometry/vector3.h +++ b/MeshConverter/src/geometry/vector3.h @@ -1,29 +1,52 @@ -#ifndef __VECTOR3_H_INCLUDED__ -#define __VECTOR3_H_INCLUDED__ +#ifndef __GEOMETRY_VECTOR3_H_INCLUDED__ +#define __GEOMETRY_VECTOR3_H_INCLUDED__ #include +#include "../common.h" -/** - * Represents a 3D vector and provides common methods/operators - * for vector math +/** + *

Represents a 3D vector and provides common methods for vector math.

+ *

Referenced/based on code from:

+ *
    + *
  • 3D Math Primer for Graphics and Game Development (Dunn & Parberry, 2002)
  • + *
  • http://www.dhpoware.com/source/mathlib.html
  • + *
  • http://www.peroxide.dk/papers/collision/collision.pdf
  • + *
+ * @author Gered */ class Vector3 { public: Vector3() {} - Vector3(float vx, float vy, float vz) { x = vx; y = vy; z = vz; } - Vector3(const float *v) { x = v[0]; y = v[1]; z = v[2]; } + + Vector3(float x, float y, float z) + { + this->x = x; + this->y = y; + this->z = z; + } + + Vector3(const float *v) + { + x = v[0]; + y = v[1]; + z = v[2]; + } + ~Vector3() {} + void Set(float x, float y, float z); + static Vector3 Cross(const Vector3 &a, const Vector3 &b); - static float Dot(const Vector3 &a, const Vector3 &b); - static Vector3 Normalize(const Vector3 &a); - static Vector3 SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3); - static float Magnitude(const Vector3 &a); - static float SquaredLength(const Vector3 &a); - static Vector3 SetLength(const Vector3 &v, float length); static float Distance(const Vector3 &a, const Vector3 &b); - static bool IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc); + static float Dot(const Vector3 &a, const Vector3 &b); + static BOOL IsPointInTriangle(const Vector3 &point, const Vector3 &a, const Vector3 &b, const Vector3 &c); + static float Length(const Vector3 &v); + static float LengthSquared(const Vector3 &v); + static Vector3 Normalize(const Vector3 &v); + static Vector3 SetLength(const Vector3 &v, float length); + static Vector3 SurfaceNormal(const Vector3 &a, const Vector3 &b, const Vector3 &c); + static Vector3 Lerp(const Vector3 &a, const Vector3 &b, float interpolation); float x; float y; @@ -46,138 +69,43 @@ Vector3 operator/(const Vector3 &left, const Vector3 &right); Vector3 &operator/=(Vector3 &left, const Vector3 &right); #define ZERO_VECTOR Vector3(0.0f, 0.0f, 0.0f) - #define X_AXIS Vector3(1.0f, 0.0f, 0.0f) #define Y_AXIS Vector3(0.0f, 1.0f, 0.0f) #define Z_AXIS Vector3(0.0f, 0.0f, 1.0f) +#define UP Vector3(0.0f, 1.0f, 0.0f) +#define DOWN Vector3(0.0f, -1.0f, 0.0f) +#define FORWARD Vector3(0.0f, 0.0f, -1.0f) +#define BACKWARD Vector3(0.0f, 0.0f, 1.0f) +#define LEFT Vector3(-1.0f, 0.0f, 0.0f) +#define RIGHT Vector3(1.0f, 0.0f, 0.0f) -#define UP_VECTOR Vector3(0.0f, 1.0f, 0.0f) +inline void Vector3::Set(float x, float y, float z) +{ + this->x = x; + this->y = y; + this->z = z; +} -/** - * Computes the cross product of 2 vectors. - * x = a.y * b.z - b.y * a.z - * y = a.z * b.x - b.z * a.x - * z = a.x * b.y - b.x * a.y - * @param a first vector +/** + * Computes the cross product of 2 vectors. + * @param a first vector * @param b second vector - * - * @return Vector3 the cross product + * @return the cross product */ inline Vector3 Vector3::Cross(const Vector3 &a, const Vector3 &b) { return Vector3( - (a.y * b.z) - (b.y * a.z), - (a.z * b.x) - (b.z * a.x), - (a.x * b.y) - (b.x * a.y) + (a.y * b.z) - (a.z * b.y), + (a.z * b.x) - (a.x * b.z), + (a.x * b.y) - (a.y * b.x) ); } /** - * Computes the dot product of 2 vectors. - * dot = (a.x * b.x) + (a.y * b.y) + (a.z * b.z) - * @param a first vector - * @param b second vector - * - * @return float the dot product - */ -inline float Vector3::Dot(const Vector3 &a, const Vector3 &b) -{ - return (a.x * b.x) + - (a.y * b.y) + - (a.z * b.z); -} - -/** - * Normalizes a vector - * x = a.x / ||a|| - * y = a.y / ||a|| - * z = a.z / ||a|| - * @param a vector to normalize - * - * @return Vector3 the normalized vector - */ -inline Vector3 Vector3::Normalize(const Vector3 &a) -{ - float magnitudeSquared = (a.x * a.x) + (a.y * a.y) + (a.z * a.z); - if (magnitudeSquared > 0.0f) - { - float inverseMagnitude = 1.0f / sqrtf(magnitudeSquared); - return Vector3( - a.x * inverseMagnitude, - a.y * inverseMagnitude, - a.z * inverseMagnitude - ); - } - else - return a; -} - -/** - * Calculates a normal vector for the given 3 vectors making up - * a triangle (counter-clockwise order) - * @param v1 first vertex - * @param v2 second vertex - * @param v3 third vertex - * - * @return Vector3 normal vector for the triangle - */ -inline Vector3 Vector3::SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) -{ - return Vector3::Normalize(Vector3::Cross(v2 - v1, v3 - v1)); -} - -/** - * Returns magnitude of a vector. - * ||a|| = sqrt((a.x * a.x) + (a.y * a.y) + (a.z * a.z)) - * @param a vector to calculate the magnitude of - * - * @return float vector magnitude - */ -inline float Vector3::Magnitude(const Vector3 &a) -{ - return sqrtf( - (a.x * a.x) + - (a.y * a.y) + - (a.z * a.z) - ); -} - -/** - * Returns the squared length of a vector (the magnitude minus - * the sqrt call) - * @param a vector to calculate the squared length of - * - * @return float squared length of the vector - */ -inline float Vector3::SquaredLength(const Vector3 &a) -{ - return - (a.x * a.x) + - (a.y * a.y) + - (a.z * a.z); -} - -/** - * Adjusts a vector so that it's magnitude is equal to the given - * length - * @param v the original vector to be adjusted - * @param length desired vector magnitude - * - * @return Vector3 the resulting vector after it's length has - * been converted to the desired amount - */ -inline Vector3 Vector3::SetLength(const Vector3 &v, float length) -{ - float magnitude = Vector3::Magnitude(v); - return v * (length / magnitude); -} - -/** - * Calculates the distance between two points + * Calculates the distance between two points. * @param a the first point * @param b the second point - * - * @return float the distance between both points + * @return the distance between both points */ inline float Vector3::Distance(const Vector3 &a, const Vector3 &b) { @@ -189,37 +117,131 @@ inline float Vector3::Distance(const Vector3 &a, const Vector3 &b) } /** - * Checks if a given point lies inside a triangle or not + * Computes the dot product of 2 vectors. + * @param a first vector + * @param b second vector + * @return the dot product + */ +inline float Vector3::Dot(const Vector3 &a, const Vector3 &b) +{ + return + (a.x * b.x) + + (a.y * b.y) + + (a.z * b.z); +} + +/** + * Checks if a given point lies inside a triangle or not. * @param point point to test * @param a first vector of the triangle * @param b second vector of the triangle * @param c third vector of the triangle - * - * @return BOOL TRUE if the point lies inside the triangle, - * FALSE if it doesn't + * @return TRUE if the point lies inside the triangle */ -inline bool Vector3::IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc) +inline BOOL Vector3::IsPointInTriangle(const Vector3 &point, const Vector3 &a, const Vector3 &b, const Vector3 &c) { - Vector3 edge1 = pb - pa; - Vector3 edge2 = pc - pa; - - float a = Vector3::Dot(edge1, edge1); - float b = Vector3::Dot(edge1, edge2); - float c = Vector3::Dot(edge2, edge2); - float ac_bb = (a * c) - (b * b); - Vector3 vp(point.x - pa.x, point.y - pa.y, point.z - pa.z); - - float d = Vector3::Dot(vp, edge1); - float e = Vector3::Dot(vp, edge2); - float x = (d * c) - (e * b); - float y = (e * a) - (d * b); - float z = x + y - ac_bb; - - int result = (( ((unsigned int&) z)& ~(((unsigned int&) x)|((unsigned int&) y)) ) & 0x80000000); - if (result == 0) - return false; + Vector3 v0 = c - a; + Vector3 v1 = b - a; + Vector3 v2 = point - a; + + float dot00 = (v0.x * v0.x) + (v0.y * v0.y) + (v0.z * v0.z); + float dot01 = (v0.x * v1.x) + (v0.y * v1.y) + (v0.z * v1.z); + float dot02 = (v0.x * v2.x) + (v0.y * v2.y) + (v0.z * v2.z); + float dot11 = (v1.x * v1.x) + (v1.y * v1.y) + (v1.z * v1.z); + float dot12 = (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); + + float denom = dot00 * dot11 - dot01 * dot01; + if (denom == 0) + return FALSE; + + float u = (dot11 * dot02 - dot01 * dot12) / denom; + float v = (dot00 * dot12 - dot01 * dot02) / denom; + + if (u >= 0 && v >= 0 && u + v <= 1) + return TRUE; else - return true; + return FALSE; +} + +/** + * Returns the length (magnitude) of a vector. + * @param v vector to calculate the length of + * @return the vector length + */ +inline float Vector3::Length(const Vector3 &v) +{ + return sqrtf( + (v.x * v.x) + + (v.y * v.y) + + (v.z * v.z) + ); +} + +/** + * Returns the squared length of a vector (the magnitude minus the sqrt + * call). + * @param v vector to calculate the squared length of + * @return squared length of the vector + */ +inline float Vector3::LengthSquared(const Vector3 &v) +{ + return + (v.x * v.x) + + (v.y * v.y) + + (v.z * v.z); +} + +/** + * Normalizes a vector. + * @param v vector to normalize + * @return the normalized vector + */ +inline Vector3 Vector3::Normalize(const Vector3 &v) +{ + float inverseLength = 1.0f / Length(v); + return Vector3( + v.x * inverseLength, + v.y * inverseLength, + v.z * inverseLength + ); +} + +/** + * Adjusts a vector so that it's length is equal to the given + * length. + * @param v the original vector to be adjusted + * @param length desired vector length (magnitude) + * @return the resulting vector after it's length has been converted to the + * desired amount + */ +inline Vector3 Vector3::SetLength(const Vector3 &v, float length) +{ + return v * (length / Length(v)); +} + +/** + * Calculates a normal vector for the given 3 vectors making up a + * triangle (counter clockwise order). + * @param a first vertex + * @param b second vertex + * @param c third vertex + * @return normal vector for the triangle + */ +inline Vector3 Vector3::SurfaceNormal(const Vector3 &a, const Vector3 &b, const Vector3 &c) +{ + return Normalize(Cross((b - a), (c - a))); +} + +/** + * Linearly interpolates between two vectors. + * @param a the first vector + * @param b the second vector + * @param interpolation the amount to interpolate + * @return Vector3 the interpolated vector + */ +inline Vector3 Vector3::Lerp(const Vector3 &a, const Vector3 &b, float interpolation) +{ + return a + (b - a) * interpolation; } inline bool operator==(const Vector3 &left, const Vector3 &right) @@ -316,4 +338,4 @@ inline Vector3 &operator/=(Vector3 &left, const Vector3 &right) return left; } -#endif \ No newline at end of file +#endif