diff options
Diffstat (limited to 'dep/g3dlite/source/Matrix4.cpp')
-rw-r--r-- | dep/g3dlite/source/Matrix4.cpp | 291 |
1 files changed, 220 insertions, 71 deletions
diff --git a/dep/g3dlite/source/Matrix4.cpp b/dep/g3dlite/source/Matrix4.cpp index fbc918f8f3e..f3b25ad5837 100644 --- a/dep/g3dlite/source/Matrix4.cpp +++ b/dep/g3dlite/source/Matrix4.cpp @@ -1,16 +1,16 @@ /** - @file Matrix4.cpp + \file G3D/source/Matrix4.cpp - - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-10-02 - @edited 2010-01-29 + \created 2003-10-02 + \edited 2012-02-19 */ #include "G3D/platform.h" #include "G3D/Matrix4.h" #include "G3D/Matrix3.h" +#include "G3D/Matrix2.h" #include "G3D/Vector4.h" #include "G3D/Vector3.h" #include "G3D/BinaryInput.h" @@ -24,11 +24,11 @@ namespace G3D { Matrix4::Matrix4(const Any& any) { - any.verifyName("Matrix4"); + any.verifyNameBeginsWith("Matrix4", "CFrame", "CoordinateFrame"); any.verifyType(Any::ARRAY); - const std::string& name = toLower(any.name()); - if (name == "matrix4") { + const std::string& name = any.name(); + if (name == "Matrix4") { any.verifySize(16); for (int r = 0; r < 4; ++r) { @@ -36,26 +36,43 @@ Matrix4::Matrix4(const Any& any) { elt[r][c] = any[r * 4 + c]; } } - } else if (name == "matrix4::scale") { + } else if (name == "Matrix4::scale") { if (any.size() == 1) { - *this = scale(any[0].number()); + *this = scale(any[0].floatValue()); } else if (any.size() == 3) { *this = scale(any[0], any[1], any[2]); } else { any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments"); } - } else if (name == "matrix4::translation") { + } else if (name == "Matrix4::rollDegrees") { + any.verifySize(1); + *this = rollDegrees(any[0].floatValue()); + } else if (name == "Matrix4::yawDegrees") { + any.verifySize(1); + *this = yawDegrees(any[0].floatValue()); + } else if (name == "Matrix4::pitchDegrees") { + any.verifySize(1); + *this = pitchDegrees(any[0].floatValue()); + } else if (name == "Matrix4::translation") { if (any.size() == 3) { *this = translation(any[0], any[1], any[2]); } else { - any.verify(false, "Matrix4::translation() takes either 1 or 3 arguments"); - } } else { + any.verify(false, "Matrix4::translation() requires 3 arguments"); + } + } else if (name == "Matrix4::diagonal") { + any.verifySize(4); + *this = diagonal(any[0], any[1], any[2], any[3]); + } else if (name == "Matrix4::identity") { + *this = identity(); + } else if (beginsWith(name, "CFrame") || beginsWith(name, "CoordinateFrame")) { + *this = CFrame(any); + } else { any.verify(false, "Expected Matrix4 constructor"); } } -Matrix4::operator Any() const { +Any Matrix4::toAny() const { Any any(Any::ARRAY, "Matrix4"); any.resize(16); for (int r = 0; r < 4; ++r) { @@ -121,6 +138,12 @@ Matrix3 Matrix4::upper3x3() const { } +Matrix2 Matrix4::upper2x2() const { + return Matrix2(elt[0][0], elt[0][1], + elt[1][0], elt[1][1]); +} + + Matrix4 Matrix4::orthogonalProjection( const class Rect2D& rect, float nearval, @@ -164,59 +187,59 @@ Matrix4 Matrix4::orthogonalProjection( Matrix4 Matrix4::perspectiveProjection( - float left, - float right, - float bottom, - float top, - float nearval, - float farval, - float upDirection) { - - float x, y, a, b, c, d; - - x = (2.0f*nearval) / (right-left); - y = (2.0f*nearval) / (top-bottom); + double left, + double right, + double bottom, + double top, + double nearval, + double farval, + float upDirection) { + + double x, y, a, b, c, d; + + x = (2.0*nearval) / (right-left); + y = (2.0*nearval) / (top-bottom); a = (right+left) / (right-left); b = (top+bottom) / (top-bottom); - if (farval >= finf()) { + if (farval >= inf()) { // Infinite view frustum - c = -1.0f; - d = -2.0f * nearval; + c = -1.0; + d = -2.0 * nearval; } else { c = -(farval+nearval) / (farval-nearval); - d = -(2.0f*farval*nearval) / (farval-nearval); + d = -(2.0*farval*nearval) / (farval-nearval); } - debugAssertM(abs(upDirection) == 1.0f, "upDirection must be -1 or +1"); + debugAssertM(abs(upDirection) == 1.0, "upDirection must be -1 or +1"); y *= upDirection; b *= upDirection; return Matrix4( - x, 0, a, 0, - 0, y, b, 0, - 0, 0, c, d, + (float)x, 0, (float)a, 0, + 0, (float)y, (float)b, 0, + 0, 0, (float)c, (float)d, 0, 0, -1, 0); } void Matrix4::getPerspectiveProjectionParameters( - float& left, - float& right, - float& bottom, - float& top, - float& nearval, - float& farval, + double& left, + double& right, + double& bottom, + double& top, + double& nearval, + double& farval, float upDirection) const { debugAssertM(abs(upDirection) == 1.0f, "upDirection must be -1 or +1"); - float x = elt[0][0]; - float y = elt[1][1] * upDirection; - float a = elt[0][2]; - float b = elt[1][2] * upDirection; - float c = elt[2][2]; - float d = elt[2][3]; + double x = elt[0][0]; + double y = elt[1][1] * upDirection; + double a = elt[0][2]; + double b = elt[1][2] * upDirection; + double c = elt[2][2]; + double d = elt[2][3]; // Verify that this really is a projection matrix debugAssertM(elt[3][2] == -1, "Not a projection matrix"); @@ -232,18 +255,18 @@ void Matrix4::getPerspectiveProjectionParameters( if (c == -1) { farval = finf(); - nearval = -d / 2.0f; + nearval = -d / 2.0; } else { - nearval = d * ((c - 1.0f) / (c + 1.0f) - 1.0f) / (-2.0f * (c - 1.0f) / (c + 1.0f)); - farval = nearval * ((c - 1.0f) / (c + 1.0f)); + nearval = d * ((c - 1.0) / (c + 1.0) - 1.0) / (-2.0 * (c - 1.0) / (c + 1.0)); + farval = nearval * ((c - 1.0) / (c + 1.0)); } - left = (a - 1.0f) * nearval / x; - right = 2.0f * nearval / x + left; + left = (a - 1.0) * nearval / x; + right = 2.0 * nearval / x + left; - bottom = (b - 1.0f) * nearval / y; - top = 2.0f * nearval / y + bottom; + bottom = (b - 1.0) * nearval / y; + top = 2.0 * nearval / y + bottom; } @@ -401,7 +424,7 @@ bool Matrix4::operator==(const Matrix4& other) const { float Matrix4::determinant() const { // Determinant is the dot product of the first row and the first row // of cofactors (i.e. the first col of the adjoint matrix) - return cofactor().row(0).dot(row(0)); + return cofactor().row(0).dot(row(0)); } @@ -417,14 +440,14 @@ Matrix4 Matrix4::inverse() const { // Determinant is the dot product of the first row and the first row // of cofactors (i.e. the first col of the adjoint matrix) - float det = A.column(0).dot(row(0)); + float det = A.column(0).dot(row(0)); - return A * (1.0f / det); + return A * (1.0f / det); } Matrix4 Matrix4::cofactor() const { - Matrix4 out; + Matrix4 out; // We'll use i to incrementally compute -1 ^ (r+c) int i = 1; @@ -482,19 +505,19 @@ float Matrix4::subDeterminant(int excludeRow, int excludeCol) const { CoordinateFrame Matrix4::approxCoordinateFrame() const { - CoordinateFrame cframe; + CoordinateFrame cframe; - for (int r = 0; r < 3; ++r) { - for (int c = 0; c < 3; ++c) { - cframe.rotation[r][c] = elt[r][c]; - } - cframe.translation[r] = elt[r][3]; - } + for (int r = 0; r < 3; ++r) { + for (int c = 0; c < 3; ++c) { + cframe.rotation[r][c] = elt[r][c]; + } + cframe.translation[r] = elt[r][3]; + } - // Ensure that the rotation matrix is orthonormal - cframe.rotation.orthonormalize(); + // Ensure that the rotation matrix is orthonormal + cframe.rotation.orthonormalize(); - return cframe; + return cframe; } @@ -517,12 +540,138 @@ void Matrix4::deserialize(class BinaryInput& b) { std::string Matrix4::toString() const { return G3D::format("[%g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g]", - elt[0][0], elt[0][1], elt[0][2], elt[0][3], - elt[1][0], elt[1][1], elt[1][2], elt[1][3], - elt[2][0], elt[2][1], elt[2][2], elt[2][3], - elt[3][0], elt[3][1], elt[3][2], elt[3][3]); + elt[0][0], elt[0][1], elt[0][2], elt[0][3], + elt[1][0], elt[1][1], elt[1][2], elt[1][3], + elt[2][0], elt[2][1], elt[2][2], elt[2][3], + elt[3][0], elt[3][1], elt[3][2], elt[3][3]); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +Matrix4float64::Matrix4float64(const Matrix4& m) { + for (int r = 0; r < 4; ++r) { + for (int c = 0; c < 4; ++c) { + elt[r][c] = m[r][c]; + } + } +} + + +Matrix4float64::Matrix4float64() { + for (int r = 0; r < 4; ++r) { + for (int c = 0; c < 4; ++c) { + elt[r][c] = 0.0; + } + } +} + + +Matrix4float64::Matrix4float64 + (double r1c1, double r1c2, double r1c3, double r1c4, + double r2c1, double r2c2, double r2c3, double r2c4, + double r3c1, double r3c2, double r3c3, double r3c4, + double r4c1, double r4c2, double r4c3, double r4c4) { + elt[0][0] = r1c1; elt[0][1] = r1c2; elt[0][2] = r1c3; elt[0][3] = r1c4; + elt[1][0] = r2c1; elt[1][1] = r2c2; elt[1][2] = r2c3; elt[1][3] = r2c4; + elt[2][0] = r3c1; elt[2][1] = r3c2; elt[2][2] = r3c3; elt[2][3] = r3c4; + elt[3][0] = r4c1; elt[3][1] = r4c2; elt[3][2] = r4c3; elt[3][3] = r4c4; +} + + +const Matrix4float64& Matrix4float64::identity() { + static Matrix4float64 m( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + return m; +} + + +const Matrix4float64& Matrix4float64::zero() { + static Matrix4float64 m; + return m; +} + + +bool Matrix4float64::operator!=(const Matrix4float64& other) const { + return ! (*this == other); +} + + +bool Matrix4float64::operator==(const Matrix4float64& other) const { + + // If the bit patterns are identical, they must be + // the same matrix. If not, they *might* still have + // equal elements due to floating point weirdness. + if (memcmp(this, &other, sizeof(Matrix4float64) == 0)) { + return true; + } + + for (int r = 0; r < 4; ++r) { + for (int c = 0; c < 4; ++c) { + if (elt[r][c] != other.elt[r][c]) { + return false; + } + } + } + + return true; } + +Vector4 Matrix4float64::operator*(const Vector4& vector) const { + Vector4 result; + for (int r = 0; r < 4; ++r) { + double sum = 0; + for (int c = 0; c < 4; ++c) { + sum += elt[r][c] * vector[c]; + } + result[r] = (float)sum; + } + + return result; +} + + +Matrix4float64 Matrix4float64::perspectiveProjection( + double left, + double right, + double bottom, + double top, + double nearval, + double farval, + float upDirection) { + double x, y, a, b, c, d; + + x = (2.0*nearval) / (right-left); + y = (2.0*nearval) / (top-bottom); + a = (right+left) / (right-left); + b = (top+bottom) / (top-bottom); + + if (farval >= inf()) { + // Infinite view frustum + c = -1.0; + d = -2.0 * nearval; + } else { + c = -(farval+nearval) / (farval-nearval); + d = -(2.0*farval*nearval) / (farval-nearval); + } + + debugAssertM(abs(upDirection) == 1.0, "upDirection must be -1 or +1"); + y *= upDirection; + b *= upDirection; + + return Matrix4float64( + (float)x, 0, (float)a, 0, + 0, (float)y, (float)b, 0, + 0, 0, (float)c, (float)d, + 0, 0, -1, 0); +} + + } // namespace |