aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/include/G3D/Matrix4.h
blob: 6b810ba77e84a617d4bc0497f8bb74cd45710c3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/**
  @file Matrix4.h
 
  4x4 matrix class
 
  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
 
  @created 2003-10-02
  @edited  2009-10-20
 */

#ifndef G3D_Matrix4_h
#define G3D_Matrix4_h

#ifdef _MSC_VER
// Disable conditional expression is constant, which occurs incorrectly on inlined functions
#   pragma warning (push)
#   pragma warning( disable : 4127 )
#endif

#include "G3D/platform.h"
#include "G3D/debugAssert.h"
#include "G3D/Matrix3.h"
#include "G3D/Vector3.h"

namespace G3D {

class Any;

/**
  A 4x4 matrix.

  See also G3D::CoordinateFrame, G3D::Matrix3, G3D::Quat
 */
class Matrix4 {
private:

    float elt[4][4];

    /**
      Computes the determinant of the 3x3 matrix that lacks excludeRow
      and excludeCol. 
    */
    float subDeterminant(int excludeRow, int excludeCol) const;

    // Hidden operators
    bool operator<(const Matrix4&) const;
    bool operator>(const Matrix4&) const;
    bool operator<=(const Matrix4&) const;
    bool operator>=(const Matrix4&) const;

public:
    /** Must be of the form: <code>Matrix4(#, #, # .... #)</code>*/
    Matrix4(const Any& any);

    operator Any() const;

    Matrix4(
        float r1c1, float r1c2, float r1c3, float r1c4,
        float r2c1, float r2c2, float r2c3, float r2c4,
        float r3c1, float r3c2, float r3c3, float r3c4,
        float r4c1, float r4c2, float r4c3, float r4c4);

    /**
     init should be <B>row major</B>.
     */
    Matrix4(const float* init);
    
	/**
		a is the upper left 3x3 submatrix and b is the upper right 3x1 submatrix. The last row of the created matrix is (0,0,0,1).
	*/
    Matrix4(const class Matrix3& upper3x3, const class Vector3& lastCol = Vector3::zero());

    Matrix4(const class CoordinateFrame& c);

    Matrix4(const double* init);

    Matrix4();

    /** Produces an RT transformation that nearly matches this Matrix4.
        Because a Matrix4 may not be precisely a rotation and translation,
        this may introduce error. */
    class CoordinateFrame approxCoordinateFrame() const;

    // Special values.
    // Intentionally not inlined: see Matrix3::identity() for details.
    static const Matrix4& identity();
    static const Matrix4& zero();

    /** If this is a perspective projection matrix created by
        Matrix4::perspectiveProjection, extract its parameters. */
    void getPerspectiveProjectionParameters
    (float& left,
     float& right,
     float& bottom,  
     float& top,
     float& nearval, 
     float& farval,
     float updirection = -1.0f) const;
        
    inline float* operator[](int r) {
        debugAssert(r >= 0);
        debugAssert(r < 4);
        return (float*)&elt[r];
    }

    inline const float* operator[](int r) const {
        debugAssert(r >= 0);
        debugAssert(r < 4);
        return (const float*)&elt[r];
    } 

    inline operator float* () {
        return (float*)&elt[0][0];
    }

    inline operator const float* () const {
        return (const float*)&elt[0][0];
    }

    Matrix4 operator*(const Matrix4& other) const;
    Matrix4 operator+(const Matrix4& other) const {
        Matrix4 result;
        for (int r = 0; r < 4; ++r) {
            for (int c = 0; c < 4; ++c) {
                result.elt[r][c] = elt[r][c] + other.elt[r][c];
            }
        }
        return result;
    }

    class Matrix3 upper3x3() const;

    /** Homogeneous multiplication. Let k = M * [v w]^T.  result = k.xyz() / k.w */
    class Vector3 homoMul(const class Vector3& v, float w) const;

    /**
     Constructs an orthogonal projection matrix from the given parameters.
     Near and far are the <b>NEGATIVE</b> of the near and far plane Z values
     (to follow OpenGL conventions).

    \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), 
    1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
     */
    static Matrix4 orthogonalProjection(
        float            left,
        float            right,
        float            bottom,
        float            top,
        float            nearval,
        float            farval,
        float            upDirection = -1.0f);


    /** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), 
    1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
      */
    static Matrix4 orthogonalProjection(
        const class Rect2D& rect,
        float            nearval,
        float            farval,
        float            upDirection = -1.0f);

    /** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), 
    1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
      */
    static Matrix4 perspectiveProjection(
        float            left,
        float            right,
        float            bottom,
        float            top,
        float            nearval,
        float            farval,
        float            upDirection = -1.0f);

    void setRow(int r, const class Vector4& v);
    void setColumn(int c, const Vector4& v);

    const Vector4& row(int r) const;
    Vector4 column(int c) const;

    Matrix4 operator*(const float s) const;
    Vector4 operator*(const Vector4& vector) const;

    Matrix4 transpose() const;

    bool operator!=(const Matrix4& other) const;
    bool operator==(const Matrix4& other) const;

    float determinant() const;
    Matrix4 inverse() const;

    /** 
     Transpose of the cofactor matrix (used in computing the inverse).
     Note: This is in fact only one type of adjoint. More generally,
     an adjoint of a matrix is any mapping of a matrix which possesses 
     certain properties.  This returns the so-called adjugate
     or classical adjoint.
    */
    Matrix4 adjoint() const;
    Matrix4 cofactor() const;

    /** Serializes row-major */
    void serialize(class BinaryOutput& b) const;
    void deserialize(class BinaryInput& b);

    std::string toString() const;

    /** 3D scale matrix */
    inline static Matrix4 scale(const Vector3& v) {
        return Matrix4(v.x, 0, 0, 0,
                       0, v.y, 0, 0,
                       0, 0, v.z, 0,
                       0, 0, 0, 1);
    }
    
    /** 3D scale matrix */
    inline static Matrix4 scale(float x, float y, float z) {
        return scale(Vector3(x, y, z));
    }

    /** 3D scale matrix */
    inline static Matrix4 scale(float s) {
        return scale(s,s,s);
    }

    /** 3D translation matrix */
    inline static Matrix4 translation(const Vector3& v) {
        return Matrix4(Matrix3::identity(), v);
    }

    inline static Matrix4 translation(float x, float y, float z) {
        return Matrix4(Matrix3::identity(), Vector3(x, y, z));
    }

    /** Create a rotation matrix that rotates \a deg degrees around the Y axis */ 
    inline static Matrix4 yawDegrees(float deg) {
        return Matrix4(Matrix3::fromAxisAngle(Vector3::unitY(), toRadians(deg)));
    }

    inline static Matrix4 pitchDegrees(float deg) {
        return Matrix4(Matrix3::fromAxisAngle(Vector3::unitX(), toRadians(deg)));
    }

    inline static Matrix4 rollDegrees(float deg) {
        return Matrix4(Matrix3::fromAxisAngle(Vector3::unitZ(), toRadians(deg)));
    }
};



} // namespace

#ifdef _MSC_VER
#   pragma warning (pop)
#endif

#endif