OXYGENHUB
◆ main openmsx / src / video / gl_transform.hh
6.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef GL_TRANSFORM_HH
2
#define GL_TRANSFORM_HH
3
4
// openGL ES 2.0 removed functions like
5
//   glRotate(), glTranslate(), glScale(), ...
6
// This code can be used to replace them.
7
//
8
// This code was inspired by the 'glm' library (though written from scratch).
9
// Compared to glm this code is much simpler but offers much less functionality.
10
//   http://glm.g-truc.net
11
12
#include "gl_mat.hh"
13
#include "gl_vec.hh"
14
15
namespace gl {
16
17
// Returns a 4x4 scaling matrix for the given xyz scale factors.
18
// Comparable to the glScale() function.
19
[[nodiscard]] constexpr mat4 scale(const vec3& xyz)
20
{
21
	return mat4(vec4(xyz, 1.0f));
22
}
23
24
// Multiplies the given matrix by a scaling matrix. Equivalent to (but more
25
// efficient than) 'A * scale(xyz)'.
26
[[nodiscard]] constexpr mat4 scale(const mat4& A, const vec3& xyz)
27
{
28
	return {A[0] * xyz.x,
29
	        A[1] * xyz.y,
30
	        A[2] * xyz.z,
31
	        A[3]};
32
}
33
34
// Returns a 4x4 translation matrix for the given xyz translation vector.
35
// Comparable to the glTranslate() function.
36
[[nodiscard]] constexpr mat4 translate(const vec3& xyz)
37
{
38
	mat4 result;
39
	result[3] = vec4(xyz, 1.0f);
40
	return result;
41
}
42
43
// Multiplies the given matrix by a translation matrix. Equivalent to (but
44
// more efficient than) 'A * translate(xyz)'.
45
[[nodiscard]] constexpr mat4 translate(mat4& A, const vec3& xyz)
46
{
47
	return {A[0],
48
	        A[1],
49
	        A[2],
50
	        A[0] * xyz.x + A[1] * xyz.y + A[2] * xyz.z + A[3]};
51
}
52
53
// Returns a 4x4 rotation matrix for rotation of the given 'angle' around the
54
// 'xyz' axis.
55
// Comparable to the glRotate() function, but with these differences:
56
//  - 'angle' is in radians instead of degrees
57
//  - 'axis' must be a normalized vector
58
[[nodiscard]] inline mat4 rotate(float angle, const vec3& axis)
59
{
60
	float s = sinf(angle);
61
	float c = cosf(angle);
62
	vec3 temp = (1.0f - c) * axis;
63
64
	return {vec4(axis.x * temp.x + c,
65
	             axis.y * temp.x + s * axis.z,
66
	             axis.z * temp.x - s * axis.y,
67
	             0.0f),
68
	        vec4(axis.x * temp.y - s * axis.z,
69
	             axis.y * temp.y + c,
70
	             axis.z * temp.y + s * axis.x,
71
	             0.0f),
72
	        vec4(axis.x * temp.z + s * axis.y,
73
	             axis.y * temp.z - s * axis.x,
74
	             axis.z * temp.z + c,
75
	             0.0f),
76
	        vec4(0.0f,
77
	             0.0f,
78
	             0.0f,
79
	             1.0f)};
80
}
81
82
// Multiplies the given matrix by a rotation matrix. Equivalent to
83
// 'A * rotate(angle, axis)'.
84
[[nodiscard]] inline mat4 rotate(const mat4& A, float angle, const vec3& axis)
85
{
86
	// TODO this could be optimized (only a little), though it's rarely used
87
	return A * rotate(angle, axis);
88
}
89
90
// Returns a 4x4 rotation matrix for rotation around the X-axis. Much more
91
// efficient than calling the generic rotate() function with a vec3(1,0,0)
92
// axis.
93
[[nodiscard]] inline mat4 rotateX(float angle)
94
{
95
	float s = sinf(angle);
96
	float c = cosf(angle);
97
	return {vec4(1.0f, 0.0f, 0.0f, 0.0f),
98
	        vec4(0.0f,  c  ,  s  , 0.0f),
99
	        vec4(0.0f, -s  ,  c  , 0.0f),
100
	        vec4(0.0f, 0.0f, 0.0f, 1.0f)};
101
}
102
103
// Multiplies the given matrix by a X-rotation matrix. Equivalent to (but more
104
// efficient than) 'A * rotateX(angle)'.
105
[[nodiscard]] inline mat4 rotateX(const mat4& A, float angle)
106
{
107
	float s = sinf(angle);
108
	float c = cosf(angle);
109
	return {A[0],
110
	        A[1] * c + A[2] * s,
111
	        A[2] * c - A[1] * s,
112
	        A[3]};
113
}
114
115
// Returns a 4x4 rotation matrix for rotation around the Y-axis. Much more
116
// efficient than calling the generic rotate() function with a vec3(0,1,0)
117
// axis.
118
[[nodiscard]] inline mat4 rotateY(float angle)
119
{
120
	float s = sinf(angle);
121
	float c = cosf(angle);
122
	return {vec4( c  , 0.0f, -s  , 0.0f),
123
	        vec4(0.0f, 1.0f, 0.0f, 0.0f),
124
	        vec4( s  , 0.0f,  c  , 0.0f),
125
	        vec4(0.0f, 0.0f, 0.0f, 1.0f)};
126
}
127
128
// Multiplies the given matrix by a Y-rotation matrix. Equivalent to (but more
129
// efficient than) 'A * rotateY(angle)'.
130
[[nodiscard]] inline mat4 rotateY(const mat4& A, float angle)
131
{
132
	float s = sinf(angle);
133
	float c = cosf(angle);
134
	return {A[0] * c - A[2] * s,
135
	        A[1],
136
	        A[2] * c + A[0] * s,
137
	        A[3]};
138
}
139
140
// Returns a 4x4 rotation matrix for rotation around the Z-axis. Much more
141
// efficient than calling the generic rotate() function with a vec3(0,0,1)
142
// axis.
143
[[nodiscard]] inline mat4 rotateZ(float angle)
144
{
145
	float s = sinf(angle);
146
	float c = cosf(angle);
147
	return {vec4( c  ,  s  , 0.0f, 0.0f),
148
	        vec4(-s  ,  c  , 0.0f, 0.0f),
149
	        vec4(0.0f, 0.0f, 1.0f, 0.0f),
150
	        vec4(0.0f, 0.0f, 0.0f, 1.0f)};
151
}
152
153
// Multiplies the given matrix by a Z-rotation matrix. Equivalent to (but more
154
// efficient than) 'A * rotateZ(angle)'.
155
[[nodiscard]] inline mat4 rotateZ(const mat4& A, float angle)
156
{
157
	float s = sinf(angle);
158
	float c = cosf(angle);
159
	return {A[0] * c + A[1] * s,
160
	        A[1] * c - A[0] * s,
161
	        A[2],
162
	        A[3]};
163
}
164
165
// Note: Don't use "near" or "far" as names since those are macros on Windows.
166
167
// Returns a 4x4 orthographic projection matrix. Comparable to
168
// the glOrtho() function.
169
[[nodiscard]] constexpr mat4 ortho(
170
	float left,    float right,
171
	float bottom,  float top,
172
	float nearVal, float farVal)
173
{
174
	return {vec4(-2.0f / (left - right),  0.0f, 0.0f, 0.0f),
175
	        vec4( 0.0f, -2.0f / (bottom - top), 0.0f, 0.0f),
176
	        vec4( 0.0f,  0.0f,  2.0f / (nearVal - farVal),  0.0f),
177
	        vec4((left    + right ) / (left    - right ),
178
	             (bottom  + top   ) / (bottom  - top   ),
179
	             (nearVal + farVal) / (nearVal - farVal),
180
	             1.0f)};
181
}
182
183
// Equivalent to calling the above ortho() function with:
184
//    ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f)
185
// In other words setup an orthographic projection with "natural screen
186
// coordinates", (0,0) the top-right corner.
187
[[nodiscard]] constexpr mat4 ortho(float width, float height)
188
{
189
	return {vec4(2.0f / width, 0.0f, 0.0f, 0.0f),
190
	        vec4(0.0f, -2.0f / height, 0.0f, 0.0f),
191
	        vec4(0.0f, 0.0f, -1.0f, 0.0f),
192
	        vec4(-1.0f, 1.0f, 0.0f, 1.0f)};
193
}
194
195
// Returns a 4x4 frustum projection matrix. Comparable to
196
// the glFrustum() function.
197
[[nodiscard]] constexpr mat4 frustum(
198
	float left,    float right,
199
	float bottom,  float top,
200
	float nearVal, float farVal)
201
{
202
	return {vec4((2.0f * nearVal) / (right - left), 0.0f, 0.0f, 0.0f),
203
	        vec4(0.0f, (2.0f * nearVal) / (top - bottom), 0.0f, 0.0f),
204
	        vec4((right   + left  ) / (right   - left  ),
205
	             (top     + bottom) / (top     - bottom),
206
	             (nearVal + farVal) / (nearVal - farVal),
207
	             -1.0f),
208
	        vec4(0.0f,
209
	             0.0f,
210
	             (2.0f * farVal * nearVal) / (nearVal - farVal),
211
	             0.0f)};
212
}
213
214
} // namespace gl
215
216
#endif