1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef API_BASE_MATH_MATRIX_H
17#define API_BASE_MATH_MATRIX_H
18
19#include <cstddef>
20
21#include <base/containers/type_traits.h>
22#include <base/math/vector.h>
23#include <base/math/vector_util.h>
24#include <base/namespace.h>
25
26// m00[0] m01[3] m02[6]
27// m10[1] m11[4] m12[7]
28// m20[2] m21[5] m22[8]
29
30// m00[0] m01[4] m02[8]  m03[12]
31// m10[1] m11[5] m12[9]  m13[13]
32// m20[2] m21[6] m22[10] m23[14]
33// m30[3] m31[7] m32[11] m33[15]
34
35// m00[0] m01[4] m02[8]
36// m10[1] m11[5] m12[9]
37// m20[2] m21[6] m22[10]
38// m30[3] m31[7] m32[11]
39BASE_BEGIN_NAMESPACE()
40namespace Math {
41#include <base/math/disable_warning_4201_heading.h>
42
43/** @ingroup group_math_matrix */
44/** Matrix 3X3 presentation in column major format */
45class Mat3X3 final {
46public:
47    union {
48        struct {
49            Vec3 x, y, z;
50        };
51        Vec3 base[3];
52        float data[9];
53    };
54
55    /** Subscript operator */
56    constexpr Vec3& operator[](size_t aIndex)
57    {
58        return base[aIndex];
59    }
60
61    /** Subscript operator */
62    constexpr const Vec3& operator[](size_t aIndex) const
63    {
64        return base[aIndex];
65    }
66
67    // Constructors
68    /** Default constructor */
69    inline constexpr Mat3X3() noexcept : data { 0 } {}
70
71    /** Identity constructor */
72    inline explicit constexpr Mat3X3(float id) noexcept : data { id, 0.0f, 0.0f, 0.0f, id, 0.0f, 0.0f, 0.0f, id } {}
73
74    /** Constructor for using Vector3's */
75    inline constexpr Mat3X3(Vec3 const& v0, Vec3 const& v1, Vec3 const& v2) noexcept : x(v0), y(v1), z(v2) {}
76
77    /** Constructor for array of floats */
78    inline constexpr Mat3X3(const float d[9]) noexcept : data { d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8] }
79    {}
80
81    inline ~Mat3X3() = default;
82
83    /** Multiply two matrices */
84    inline constexpr Mat3X3 operator*(const Mat3X3& rhs) const
85    {
86        const Vec3& rha { rhs.x.x, rhs.y.x, rhs.z.x };
87        const Vec3& rhb { rhs.x.y, rhs.y.y, rhs.z.y };
88        const Vec3& rhc { rhs.x.z, rhs.y.z, rhs.z.z };
89
90        return { { Dot(x, rha), Dot(x, rhb), Dot(x, rhc) }, { Dot(y, rha), Dot(y, rhb), Dot(y, rhc) },
91            { Dot(z, rha), Dot(z, rhb), Dot(z, rhc) } };
92    }
93
94    /** Multiply columns by float scalar value */
95    inline constexpr Mat3X3 operator*(const float& scalar) const
96    {
97        return Mat3X3(x * scalar, y * scalar, z * scalar);
98    }
99
100    /** Equality operator, returns true if matrices are equal */
101    inline constexpr bool operator==(const Mat3X3& mat) const
102    {
103        for (size_t i = 0; i < countof(data); ++i) {
104            if (data[i] != mat.data[i]) {
105                return false;
106            }
107        }
108        return true;
109    }
110
111    /** Inequality operator, returns true if matrices are inequal */
112    inline constexpr bool operator!=(const Mat3X3& mat) const
113    {
114        for (size_t i = 0; i < countof(data); ++i) {
115            if (data[i] != mat.data[i]) {
116                return true;
117            }
118        }
119        return false;
120    }
121};
122
123// Assert that Mat3X3 is the same as 9 floats
124static_assert(sizeof(Mat3X3) == 9 * sizeof(float));
125
126static constexpr Mat3X3 IDENTITY_3X3(1.f);
127
128/** @ingroup group_math_matrix */
129/** Matrix 4X4 presentation in column major format */
130class Mat4X4 final {
131public:
132    union {
133        struct {
134            Vec4 x, y, z, w;
135        };
136        Vec4 base[4]; // base[0] is X ,base [1] is Y, etc..
137        float data[16];
138    };
139
140    // "For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory.
141    // The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix."
142    // https://www.khronos.org/opengl/wiki/General_OpenGL:_Transformations#Are_OpenGL_matrices_column-major_or_row-major.3F
143    // this is also the same as with glm.
144    /** Subscript operator */
145    constexpr Vec4& operator[](size_t aIndex)
146    {
147        return base[aIndex];
148    }
149
150    /** Subscript operator */
151    constexpr const Vec4& operator[](size_t aIndex) const
152    {
153        return base[aIndex];
154    }
155
156    // Constructors
157    /** Zero initializer constructor */
158    inline constexpr Mat4X4() : data { 0 } {}
159
160    /** Constructor for Vector4's */
161    inline constexpr Mat4X4(Vec4 const& v0, Vec4 const& v1, Vec4 const& v2, Vec4 const& v3) : x(v0), y(v1), z(v2), w(v3)
162    {}
163
164    /** Constructor for array of floats */
165    inline constexpr Mat4X4(const float d[16])
166        : data { d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15] }
167    {}
168
169    /** Constructor for floats */
170    inline constexpr Mat4X4(float d0, float d1, float d2, float d3, float d4, float d5, float d6, float d7, float d8,
171        float d9, float d10, float d11, float d12, float d13, float d14, float d15)
172        : data { d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15 }
173    {}
174
175    /** Identity constructor */
176    inline explicit constexpr Mat4X4(float id)
177        : data { id, 0.0f, 0.0f, 0.0f, 0.0f, id, 0.0f, 0.0f, 0.0f, 0.0f, id, 0.0f, 0.0f, 0.0f, 0.0f, id }
178    {}
179
180    /** Conversion constructor from Mat3X3 to Mat4X4 */
181    explicit inline constexpr Mat4X4(const Mat3X3& mat3X3)
182        : data { mat3X3.data[0], mat3X3.data[1], mat3X3.data[2], 0.0f, mat3X3.data[3], mat3X3.data[4], mat3X3.data[5],
183              0.0f, mat3X3.data[6], mat3X3.data[7], mat3X3.data[8], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }
184    {}
185
186    inline ~Mat4X4() = default;
187
188    /** Multiply two matrices */
189    inline constexpr Mat4X4 operator*(const Mat4X4& rhs) const
190    {
191#define d data
192        Mat4X4 res;
193        res.d[0] = d[0] * rhs.d[0] + d[4] * rhs.d[1] + d[8] * rhs.d[2] + d[12] * rhs.d[3];
194        res.d[4] = d[0] * rhs.d[4] + d[4] * rhs.d[5] + d[8] * rhs.d[6] + d[12] * rhs.d[7];
195        res.d[8] = d[0] * rhs.d[8] + d[4] * rhs.d[9] + d[8] * rhs.d[10] + d[12] * rhs.d[11];
196        res.d[12] = d[0] * rhs.d[12] + d[4] * rhs.d[13] + d[8] * rhs.d[14] + d[12] * rhs.d[15];
197
198        res.d[1] = d[1] * rhs.d[0] + d[5] * rhs.d[1] + d[9] * rhs.d[2] + d[13] * rhs.d[3];
199        res.d[5] = d[1] * rhs.d[4] + d[5] * rhs.d[5] + d[9] * rhs.d[6] + d[13] * rhs.d[7];
200        res.d[9] = d[1] * rhs.d[8] + d[5] * rhs.d[9] + d[9] * rhs.d[10] + d[13] * rhs.d[11];
201        res.d[13] = d[1] * rhs.d[12] + d[5] * rhs.d[13] + d[9] * rhs.d[14] + d[13] * rhs.d[15];
202
203        res.d[2] = d[2] * rhs.d[0] + d[6] * rhs.d[1] + d[10] * rhs.d[2] + d[14] * rhs.d[3];
204        res.d[6] = d[2] * rhs.d[4] + d[6] * rhs.d[5] + d[10] * rhs.d[6] + d[14] * rhs.d[7];
205        res.d[10] = d[2] * rhs.d[8] + d[6] * rhs.d[9] + d[10] * rhs.d[10] + d[14] * rhs.d[11];
206        res.d[14] = d[2] * rhs.d[12] + d[6] * rhs.d[13] + d[10] * rhs.d[14] + d[14] * rhs.d[15];
207
208        res.d[3] = d[3] * rhs.d[0] + d[7] * rhs.d[1] + d[11] * rhs.d[2] + d[15] * rhs.d[3];
209        res.d[7] = d[3] * rhs.d[4] + d[7] * rhs.d[5] + d[11] * rhs.d[6] + d[15] * rhs.d[7];
210        res.d[11] = d[3] * rhs.d[8] + d[7] * rhs.d[9] + d[11] * rhs.d[10] + d[15] * rhs.d[11];
211        res.d[15] = d[3] * rhs.d[12] + d[7] * rhs.d[13] + d[11] * rhs.d[14] + d[15] * rhs.d[15];
212#undef d
213        return res;
214    }
215
216    /** Multiply columns by float scalar value */
217    inline constexpr Mat4X4 operator*(const float& scalar) const
218    {
219        return Mat4X4(x * scalar, y * scalar, z * scalar, w * scalar);
220    }
221
222    /** Equality operator, returns true if matrices are equal */
223    inline constexpr bool operator==(const Mat4X4& mat) const
224    {
225        for (size_t i = 0; i < countof(data); ++i) {
226            if (data[i] != mat.data[i]) {
227                return false;
228            }
229        }
230        return true;
231    }
232
233    /** Inequality operator, returns true if matrices are inequal */
234    inline constexpr bool operator!=(const Mat4X4& mat) const
235    {
236        for (size_t i = 0; i < countof(data); ++i) {
237            if (data[i] != mat.data[i]) {
238                return true;
239            }
240        }
241        return false;
242    }
243};
244
245// Assert that Mat4X4 is the same as 16 floats
246static_assert(sizeof(Mat4X4) == 16 * sizeof(float));
247
248static constexpr Mat4X4 IDENTITY_4X4(1.f);
249
250/** @ingroup group_math_matrix */
251/** Matrix 4X3 presentation in column major format */
252class Mat4X3 final {
253public:
254    union {
255        struct {
256            Vec3 x, y, z, w;
257        };
258        Vec3 base[4]; // base[0] is X ,base [1] is Y, etc..
259        float data[12];
260    };
261
262    // "For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory.
263    // The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix."
264    // https://www.khronos.org/opengl/wiki/General_OpenGL:_Transformations#Are_OpenGL_matrices_column-major_or_row-major.3F
265    // this is also the same as with glm.
266    /** Subscript operator */
267    constexpr Vec3& operator[](size_t aIndex)
268    {
269        return base[aIndex];
270    }
271
272    /** Subscript operator */
273    constexpr const Vec3& operator[](size_t aIndex) const
274    {
275        return base[aIndex];
276    }
277
278    // Constructors
279    /** Zero initializer constructor */
280    inline constexpr Mat4X3() : data { 0 } {}
281
282    /** Constructor for Vector4's */
283    inline constexpr Mat4X3(Vec3 const& v0, Vec3 const& v1, Vec3 const& v2, Vec3 const& v3) : x(v0), y(v1), z(v2), w(v3)
284    {}
285
286    /** Constructor for array of floats */
287    inline constexpr Mat4X3(const float d[12])
288        : data { d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11] }
289    {}
290
291    /** Constructor for floats */
292    inline constexpr Mat4X3(float d0, float d1, float d2, float d3, float d4, float d5, float d6, float d7, float d8,
293        float d9, float d10, float d11)
294        : data { d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11 }
295    {}
296
297    /** Identity constructor */
298    inline explicit constexpr Mat4X3(float id)
299        : data { id, 0.0f, 0.0f, 0.0f, id, 0.0f, 0.0f, 0.0f, id, 0.0f, 0.0f, 0.0f }
300    {}
301
302    inline ~Mat4X3() = default;
303
304    /** Multiply columns by float scalar value */
305    inline constexpr Mat4X3 operator*(const float& scalar) const
306    {
307        return Mat4X3(x * scalar, y * scalar, z * scalar, w * scalar);
308    }
309
310    /** Equality operator, returns true if matrices are equal */
311    inline constexpr bool operator==(const Mat4X3& mat) const
312    {
313        for (size_t i = 0; i < countof(data); ++i) {
314            if (data[i] != mat.data[i]) {
315                return false;
316            }
317        }
318        return true;
319    }
320
321    /** Inequality operator, returns true if matrices are inequal */
322    inline constexpr bool operator!=(const Mat4X3& mat) const
323    {
324        for (size_t i = 0; i < countof(data); ++i) {
325            if (data[i] != mat.data[i]) {
326                return true;
327            }
328        }
329        return false;
330    }
331};
332
333// Assert that Mat4X4 is the same as 12 floats
334static_assert(sizeof(Mat4X3) == 12 * sizeof(float));
335
336static constexpr Mat4X3 IDENTITY_4X3(1.f);
337
338#include <base/math/disable_warning_4201_footer.h>
339} // namespace Math
340BASE_END_NAMESPACE()
341
342#endif // API_BASE_MATH_MATRIX_H
343