-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmath.h
318 lines (254 loc) · 10.9 KB
/
math.h
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
#include <cmath>
// Matrices are column-major.
//
// Coordinate system conventions:
// +x = right
// +y = down
// +z = into screen
// this is a bit unorthodox but right-handed and convenient.
#define IMPL_COMPONENT_OP2(op) \
this_type& operator op(const this_type& b) { x op b.x; y op b.y; return *this; }
#define IMPL_COMPONENT_OP3(op) \
this_type& operator op(const this_type& b) { x op b.x; y op b.y; z op b.z; return *this; }
#define IMPL_COMPONENT_OP4(op) \
this_type& operator op(const this_type& b) { x op b.x; y op b.y; z op b.z; w op b.w; return *this; }
#define IMPL_LINEAR_OPS(type) \
template<typename T> type<T> operator -(const type<T>& v) { type<T> x = v; x *= T(-1); return x; } \
template<typename T> type<T> operator +(const type<T>& a, const type<T>& b) { type<T> x = a; x += b; return x; } \
template<typename T> type<T> operator -(const type<T>& a, const type<T>& b) { type<T> x = a; x -= b; return x; } \
template<typename T> type<T> operator *(const type<T>& a, T s) { type<T> x = a; x *= s; return x; } \
template<typename T> type<T> operator *(const type<T>& a, const type<T>& b) { type<T> x = a; x *= b; return x; } \
template<typename T> type<T> operator *(T s, const type<T>& b) { type<T> x = b; x *= s; return x; }
#define IMPL_VECTOR_OPS(type, dot_expr) \
IMPL_LINEAR_OPS(type) \
template<typename T> T dot(const type<T>& a, const type<T>& b) { return dot_expr; } \
template<typename T> T len_sq(const type<T>& a) { return dot(a, a); } \
template<typename T> T len(const type<T>& a) { return std::sqrt(len_sq(a)); } \
template<typename T> type<T> normalize(const type<T>& a) { return rsqrt(len_sq(a)) * a; }
#define IMPL_MATRIX_OPS(mat_type, vec_type, mul_expr) \
IMPL_LINEAR_OPS(mat_type) \
template<typename T> vec_type<T> operator *(const mat_type<T>& m, const vec_type<T>& v) { return mul_expr; }
namespace math {
template<typename T>
T rsqrt(T x)
{
return T(1) / std::sqrt(x);
}
template<typename T>
struct vec2T {
typedef vec2T<T> this_type;
union {
struct {
T x, y;
};
T v[2];
};
vec2T() {}
explicit vec2T(T s) : x(s), y(s) {}
vec2T(T x, T y) : x(x), y(y) {}
T operator[](int i) const { return v[i]; }
T& operator[](int i) { return v[i]; }
IMPL_COMPONENT_OP2(+=)
IMPL_COMPONENT_OP2(-=)
IMPL_COMPONENT_OP2(*=)
this_type& operator *=(T s) { x *= s; y *= s; return *this; }
};
IMPL_VECTOR_OPS(vec2T, a.x*b.x + a.y*b.y)
template<typename T>
struct vec3T {
typedef vec3T<T> this_type;
union {
struct {
T x, y, z;
};
T v[3];
};
vec3T() {}
explicit vec3T(T s) : x(s), y(s), z(s) {}
vec3T(T x, T y, T z) : x(x), y(y), z(z) {}
T operator[](int i) const { return v[i]; }
T& operator[](int i) { return v[i]; }
IMPL_COMPONENT_OP3(+=)
IMPL_COMPONENT_OP3(-=)
IMPL_COMPONENT_OP3(*=)
this_type& operator *=(T s) { x *= s; y *= s; z *= s; return *this; }
};
IMPL_VECTOR_OPS(vec3T, a.x*b.x + a.y*b.y + a.z*b.z)
template<typename T>
vec3T<T> cross(const vec3T<T>& a, const vec3T<T>& b)
{
return vec3T<T>(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}
template<typename T>
struct vec4T {
typedef vec4T<T> this_type;
union {
struct {
T x, y, z, w;
};
T v[4];
};
vec4T() {}
explicit vec4T(T s) : x(s), y(s), z(s), w(s) {}
vec4T(const vec3T<T>& v, T w) : x(v.x), y(v.y), z(v.z), w(w) {}
vec4T(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
T operator[](int i) const { return v[i]; }
T& operator[](int i) { return v[i]; }
IMPL_COMPONENT_OP4(+=)
IMPL_COMPONENT_OP4(-=)
IMPL_COMPONENT_OP4(*=)
this_type& operator *=(T s) { x *= s; y *= s; z *= s; w *= s; return *this; }
};
IMPL_VECTOR_OPS(vec4T, a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w)
template<typename T>
struct mat33T {
typedef vec3T<T> vec_type;
typedef mat33T<T> this_type;
vec_type x, y, z; // columns
mat33T() {}
mat33T(const vec_type& colX, const vec_type& colY, const vec_type& colZ) : x(colX), y(colY), z(colZ) {}
mat33T(
T _00, T _01, T _02,
T _10, T _11, T _12,
T _20, T _21, T _22
) : x(_00, _10, _20), y(_01, _11, _21), z(_02, _12, _22) {}
T operator()(int i, int j) const { return (&x)[j][i]; }
T& operator()(int i, int j) { return (&x)[j][i]; }
const vec_type& get_col(int i) const { return (&x)[i]; }
void set_col(int i, const vec_type& v) { (&x)[i] = v; }
const vec_type get_row(int i) const { return vec_type((&x)[0][i], (&x)[1][i], (&x)[2][i]); }
void set_row(int i, const vec_type& v) { (&x)[0][i] = v.x; (&x)[1][i] = v.y; (&x)[2][i] = v.z; }
IMPL_COMPONENT_OP3(+=)
IMPL_COMPONENT_OP3(-=)
this_type& operator *=(T s) { x *= s; y *= s; z *= s; return *this; }
this_type& operator *=(const this_type& b);
static this_type diag(T x, T y, T z) { return mat33T(x, T(0), T(0), T(0), y, T(0), T(0), T(0), z); }
static this_type identity() { return diag(T(1), T(1), T(1)); }
static this_type uniform_scale(T s) { return diag(s, s, s); }
static this_type rotation(const vec_type& axis, T angle)
{
// Rodrigues rotation formula
T cosv = std::cos(angle);
vec_type sa = std::sin(angle) * axis;
vec_type omca = (T(1) - cosv) * axis;
return mat33T(
omca.x*axis.x + cosv, omca.x*axis.y - sa.z, omca.x*axis.z + sa.y,
omca.y*axis.x + sa.z, omca.y*axis.y + cosv, omca.y*axis.z - sa.x,
omca.z*axis.x - sa.y, omca.z*axis.y + sa.x, omca.z*axis.z + cosv
);
}
};
IMPL_MATRIX_OPS(mat33T, vec3T, v.x*m.x + v.y*m.y + v.z*m.z)
template<typename T>
mat33T<T>& mat33T<T>::operator *=(const mat33T<T>& b)
{
const mat33T<T> M = *this;
x = M * b.x;
y = M * b.y;
z = M * b.z;
w = M * b.w;
return *this;
}
template<typename T>
mat33T<T> transpose(const mat33T<T>& m)
{
return mat33T<T>(m.get_row(0), m.get_row(1), m.get_row(2));
}
template<typename T>
struct mat44T {
typedef vec4T<T> vec_type;
typedef vec3T<T> vec3_type;
typedef mat44T<T> this_type;
vec_type x, y, z, w; // columns
mat44T() {}
mat44T(const vec_type& colX, const vec_type& colY, const vec_type& colZ, const vec_type& colW) : x(colX), y(colY), z(colZ), w(colW) {}
mat44T(const mat33T<T>& mat3x3, const vec3_type& translate) : x(mat3x3.x, T(0)), y(mat3x3.y, T(0)), z(mat3x3.z, T(0)), w(translate, T(1)) {}
mat44T(
T _00, T _01, T _02, T _03,
T _10, T _11, T _12, T _13,
T _20, T _21, T _22, T _23,
T _30, T _31, T _32, T _33
) : x(_00, _10, _20, _30), y(_01, _11, _21, _31), z(_02, _12, _22, _32), w(_03, _13, _23, _33) {}
T operator()(int i, int j) const { return (&x)[j][i]; }
T& operator()(int i, int j) { return (&x)[j][i]; }
const vec_type& get_col(int i) const { return (&x)[i]; }
void set_col(int i, const vec_type& v) { (&x)[i] = v; }
const vec_type get_row(int i) const { return vec_type((&x)[0][i], (&x)[1][i], (&x)[2][i], (&x)[3][i]); }
void set_row(int i, const vec_type& v) { (&x)[0][i] = v.x; (&x)[1][i] = v.y; (&x)[2][i] = v.z; (&x)[3][i] = v.w; }
IMPL_COMPONENT_OP4(+=)
IMPL_COMPONENT_OP4(-=)
this_type& operator *=(T s) { x *= s; y *= s; z *= s; w *= s; return *this; }
this_type& operator *=(const this_type& b);
static this_type diag(T x, T y, T z, T w) { return mat44T(x, T(0), T(0), T(0), T(0), y, T(0), T(0), T(0), T(0), z, T(0), T(0), T(0), T(0), w); }
static this_type identity() { return diag(T(1), T(1), T(1), T(1)); }
static this_type look_at(const vec3_type& pos, const vec3_type& look_at, const vec3_type& down)
{
mat33T<T> M;
vec3_type z_axis = normalize(look_at - pos);
vec3_type x_axis = normalize(cross(down, z_axis));
vec3_type y_axis = cross(z_axis, x_axis);
M.set_row(0, x_axis);
M.set_row(1, y_axis);
M.set_row(2, z_axis);
return this_type(M, M * -pos);
}
static this_type orthoD3D(T lft, T rgt, T top, T bot, T nearv, T farv)
{
vec3_type mid((lft + rgt) / T(2), (bot + top) / T(2), (nearv + farv) / T(2));
T sx = T(2) / (rgt - lft);
T sy = T(2) / (top - bot);
T sz = T(1) / (farv - nearv);
return this_type(mat33T<T>::diag(sx, sy, sz), vec3T<T>(-mid.x * sx, -mid.y * sy, T(0.5) - mid.z * sz));
}
// NOTE: this takes lft/rgt/bot/top at z=1 plane, not near plane!
static this_type frustumD3D(T lft, T rgt, T top, T bot, T nearv, T farv)
{
T Q = farv / (farv - nearv);
return this_type(
T(2) / (rgt - lft), 0, (rgt + lft) / (rgt - lft), T(0),
T(0), T(2) / (top - bot), (top + bot) / (top - bot), T(0),
T(0), T(0), Q, -nearv * Q,
T(0), T(0), T(1), T(0)
);
}
// w/h at z=1 plane, not near plane!
static this_type perspectiveD3D(T w, T h, T nearv, T farv)
{
T wh = w / T(2);
T hh = h / T(2);
return frustumD3D(-wh, wh, -hh, hh, nearv, farv);
}
};
IMPL_MATRIX_OPS(mat44T, vec4T, v.x*m.x + v.y*m.y + v.z*m.z + v.w*m.w)
template<typename T>
mat44T<T>& mat44T<T>::operator *=(const mat44T<T>& b)
{
const mat44T<T> M = *this;
x = M * b.x;
y = M * b.y;
z = M * b.z;
w = M * b.w;
return *this;
}
template<typename T>
mat44T<T> transpose(const mat44T<T>& m)
{
return mat44T<T>(m.get_row(0), m.get_row(1), m.get_row(2), m.get_row(3));
}
typedef vec2T<int> vec2i;
typedef vec2T<float> vec2;
typedef vec3T<int> vec3i;
typedef vec3T<float> vec3;
typedef vec4T<int> vec4i;
typedef vec4T<float> vec4;
typedef mat33T<float> mat33;
typedef mat44T<float> mat44;
}
#undef IMPL_COMPONENT_OP2
#undef IMPL_COMPONENT_OP3
#undef IMPL_COMPONENT_OP4
#undef IMPL_LINEAR_OPS
#undef IMPL_VECTOR_OPS
#endif // MATH_H_INCLUDED