git.s-ol.nu ~forks/glm-zig / 950ba85
Initial commit Alexis Brodeur 1 year, 3 months ago
8 changed file(s) with 623 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 root = true
1
2 [*]
3 insert_final_newline = true
4 trim_trailing_whitespace = true
5 charset = utf-8
6
7 [*.zig]
8 indent_style = space
9 indent_size = 2
0 # Created by https://www.gitignore.io/api/zig
1 # Edit at https://www.gitignore.io/?templates=zig
2
3 ### zig ###
4 # Zig programming language
5
6 zig-cache/
7 build/
8 build-*/
9 docgen_tmp/
10
11 # End of https://www.gitignore.io/api/zig
12
0 # Zig GLM
1
2 A GLM alternative for the zig programming language.
3
4 ## Installation
5
6 Execute the following from your project root to install the library. Note that
7 the `dependencies` can be replaced with any other directory.
8
9 ```sh
10 mkdir -p dependencies
11 git submodules add https://github.com/ziglang-contrib/glm dependencies/glm
12 cd dependencies/glm
13 git checkout v1.0.0
14 cd ../..
15 ```
16
17 Add the following to your `build.zig` (replacing `exe` with the actual build step that requires this library):
18
19 ```zig
20 exe.addPackagePath("glm", "dependencies/glm/glm.zig");
21 ```
0 const Builder = @import("std").build.Builder;
1
2 pub fn build(b: *Builder) void {
3 const mode = b.standardReleaseOptions();
4 const lib = b.addStaticLibrary("glm", "src/main.zig");
5 lib.setBuildMode(mode);
6 lib.install();
7
8 var main_tests = b.addTest("src/main.zig");
9 main_tests.setBuildMode(mode);
10
11 const test_step = b.step("test", "Run library tests");
12 test_step.dependOn(&main_tests.step);
13 }
0 export usingnamespace @import("./src/main.zig");
0 const std = @import("std");
1 const testing = std.testing;
2 const math = std.math;
3
4 const vector = @import("./vector.zig");
5 const matrix = @import("./matrix.zig");
6
7 pub const Matrix = matrix.Matrix;
8 pub const Vector = vector.Vector;
9
10 pub const Vec2 = Vector(2);
11 pub const Vec3 = Vector(3);
12 pub const Vec4 = Vector(4);
13
14 pub const Mat2 = Matrix(2);
15 pub const Mat3 = Matrix(3);
16 pub const Mat4 = Matrix(4);
17
18 pub fn translation(v: Vec3) Mat4 {
19 return .{
20 .values = [4][4]f32 {
21 .{ 1, 0, 0, 0 },
22 .{ 0, 1, 0, 0 },
23 .{ 0, 0, 1, 0 },
24 .{ v.values[0], v.values[1], v.values[2], 1 }
25 }
26 };
27 }
28
29 pub fn rotation(angle: f32, axis: Vec3) Mat4 {
30 const unit = axis.normalize();
31
32 const x = unit.values[0];
33 const y = unit.values[1];
34 const z = unit.values[2];
35
36 const a = math.cos(angle) + x * x * (1 - math.cos(angle));
37 const b = y * x * (1 - math.cos(angle)) + z * math.sin(angle);
38 const c = z * x * (1 - math.cos(angle)) - y * math.sin(angle);
39
40 const d = x * y * (1 - math.cos(angle)) - z * math.sin(angle);
41 const e = math.cos(angle) + y * y * (1 - math.cos(angle));
42 const f = z * y * (1 - math.cos(angle)) + x * math.sin(angle);
43
44 const h = x * z * (1 - math.cos(angle)) + y * math.sin(angle);
45 const i = y * z * (1 - math.cos(angle)) - x * math.sin(angle);
46 const j = math.cos(angle) + z * z * (1 - math.cos(angle));
47
48 return .{
49 .values = [4][4]f32{
50 .{ a, b, c, 0 },
51 .{ d, e, f, 0 },
52 .{ h, i, j, 0 },
53 .{ 0, 0, 0, 1 },
54 },
55 };
56 }
57
58 pub fn scale(v: Vec3) Mat4 {
59 return .{
60 .values = [4][4]f32 {
61 .{ v.values[0], 0, 0, 0 },
62 .{ 0, v.values[1], 0, 0 },
63 .{ 0, 0, v.values[2], 0 },
64 .{ 0, 0, 0, 1 },
65 }
66 };
67 }
68
69 pub fn lookAt(eye: Vec3, center: Vec3, up: Vec3) Mat4 {
70 const f = center.sub(eye).normalize();
71 const s = f.cross(up).normalize();
72 const u = s.cross(f);
73
74 return Mat4{
75 .values = [4][4]f32{
76 .{ s.values[0], u.values[0], -f.values[0], 0.0 },
77 .{ s.values[1], u.values[1], -f.values[1], 0.0 },
78 .{ s.values[2], u.values[2], -f.values[2], 0.0 },
79 .{ -s.dot(eye), -u.dot(eye), f.dot(eye), 1.0 },
80 },
81 };
82 }
83
84 pub fn perspective(fovY: f32, aspectRatio: f32, zNear: f32, zFar: f32) Mat4 {
85 const f = math.tan(fovY / 2.0);
86
87 const a = 1.0 / (aspectRatio * f);
88 const b = 1.0 / f;
89 const c = -(zFar + zNear) / (zFar - zNear);
90 const d = -(2.0 * zFar * zNear) / (zFar - zNear);
91
92 return .{
93 .values = [4][4]f32{
94 .{ a, 0.0, 0.0, 0.0 },
95 .{ 0.0, b, 0.0, 0.0 },
96 .{ 0.0, 0.0, c, -1.0 },
97 .{ 0.0, 0.0, d, 0.0 },
98 },
99 };
100 }
101
102 pub fn orthogonal(left: f32, right: f32, bottom: f32, top: f32, zNear: f32, zFar: f32) Mat4 {
103 const a = 2.0 / (right - left);
104 const b = 2.0 / (top - bottom);
105 const c = -2.0 / (zFar - zNear);
106 const d = -(right + left) / (right - left);
107 const e = -(top + bottom) / (top - bottom);
108 const f = -(zFar + zNear) / (zFar - zNear);
109
110 return .{
111 .values = [4][4]f32{
112 .{ a, 0.0, 0.0, 0.0 },
113 .{ 0.0, b, 0.0, 0.0 },
114 .{ 0.0, 0.0, c, -1.0 },
115 .{ d, e, f, 0.0 },
116 },
117 };
118 }
119
120 test "glm" {
121 _ = @import("./vector.zig");
122 _ = @import("./matrix.zig");
123 }
0 const std = @import("std");
1 const math = std.math;
2 const testing = std.testing;
3
4 pub fn Matrix(comptime N: usize) type {
5 return packed struct {
6 const Self = @This();
7 pub const Scalar = f32;
8
9 values: [N][N]Scalar,
10
11 /// Initialies a matrix.
12 pub fn init(values: [N][N]Scalar) Self {
13 return .{ .values = values };
14 }
15
16 /// Creates a matrix filled with the given value.
17 pub fn filled(n: Scalar) Self {
18 var result: Self = undefined;
19
20 comptime var i = 0;
21 inline while (i < N) : (i += 1) {
22 comptime var j = 0;
23 inline while (j < N) : (j += 1) {
24 result.values[i][j] = n;
25 }
26 }
27
28 return result;
29 }
30
31 /// A zero initialized matrix.
32 pub const ZERO: Self = comptime Self.filled(0);
33
34 /// An identity initialized matrix.
35 pub const IDENTITY: Self = comptime brk: {
36 var result: Self = undefined;
37
38 comptime var i = 0;
39 while (i < N) : (i += 1) {
40 comptime var j = 0;
41 while (j < N) : (j += 1) {
42 result.values[i][j] = brk: {
43 if (i == j) {
44 break :brk 1;
45 } else {
46 break :brk 0;
47 }
48 };
49 }
50 }
51
52 break :brk result;
53 };
54
55 /// Transposes this matrix
56 pub fn transpose(self: Self) Self {
57 var result: Self = undefined;
58
59 comptime var i = 0;
60 inline while (i < N) : (i += 1) {
61 comptime var j = 0;
62 inline while (j < N) : (j += 1) {
63 result.values[j][i] = self.values[i][j];
64 }
65 }
66
67 return result;
68 }
69
70 /// Multiplies 2 matrices together.
71 pub fn mul(self: Self, other: Self) Self {
72 var result: Self = undefined;
73
74 const a = self.transpose();
75 const b = other;
76
77 comptime var i = 0;
78 inline while (i < N) : (i += 1) {
79 comptime var j = 0;
80 inline while (j < N) : (j += 1) {
81 const row: @Vector(N, Scalar) = a.values[j];
82 const column: @Vector(N, Scalar) = b.values[i];
83 const products: [N]Scalar = row * column;
84
85 var sum = @floatCast(f32, 0);
86 comptime var k = 0;
87 inline while (k < N) : (k += 1) {
88 sum += products[k];
89 }
90
91 result.values[i][j] = sum;
92 }
93 }
94
95 return result;
96 }
97 };
98 }
99
100 fn expectMatrixEqual(comptime N: usize, expected: [N][N]f32, actual: Matrix(N)) void {
101 comptime var i = 0;
102 inline while (i < N) : (i += 1) {
103 comptime var j = 0;
104 inline while (j < N) : (j += 1) {
105 testing.expectEqual(expected[i][j], actual.values[i][j]);
106 }
107 }
108 }
109
110 test "matrix initialization" {
111 const A = Matrix(2).init(.{ .{ 1, 2 }, .{ 3, 4 } });
112 expectMatrixEqual(2, [2][2]f32{ .{ 1, 2, }, .{ 3, 4 } }, A);
113 }
114
115 test "matrix zero" {
116 expectMatrixEqual(3, Matrix(3).filled(0).values, Matrix(3).ZERO);
117 }
118
119 test "matrix identity" {
120 expectMatrixEqual(3, [3][3]f32{ .{ 1, 0, 0 }, .{ 0, 1 , 0 }, .{ 0, 0, 1 } }, Matrix(3).IDENTITY);
121 }
122
123 test "matrix transpose" {
124 const actual = Matrix(3).init(.{ .{ 1, 2, 3 }, .{ 4, 5, 6 }, .{ 7, 8, 9 } });
125 const expected = [3][3]f32{ .{ 1, 4, 7 }, .{ 2, 5, 8 }, .{ 3, 6, 9 } };
126 expectMatrixEqual(3, expected, actual.transpose());
127 }
128
129 test "matrix multiplication" {
130 const A = Matrix(2).init(.{ .{ 1, 2 }, .{ 3, 4 } });
131 const B = Matrix(2).init(.{ .{ 6, 7 }, .{ 8, 9 } });
132 const expected = [2][2]f32{ .{ 27, 40 }, .{ 35, 52 } };
133 expectMatrixEqual(2, expected, A.mul(B));
134 }
0 const std = @import("std");
1 const math = std.math;
2
3 /// The type of a vector.
4 pub fn Vector(comptime N: usize) type {
5 return packed struct {
6 const Self = @This();
7 /// The scalar type manager by this vector.
8 pub const Scalar = f32;
9
10 values: [N]Scalar,
11
12 /// Initializes a vector from its scalar values.
13 pub fn init(values: [N]Scalar) Self {
14 return .{ .values = values };
15 }
16
17 /// Creates a vector filled with the given scalar value.
18 pub fn filled(n: Scalar) Self {
19 var values: [N]Scalar = undefined;
20 comptime var i = 0;
21 inline while (i < N) : (i += 1) {
22 values[i] = n;
23 }
24 return .{ .values = values };
25 }
26
27 /// Creates a vector filled with zeroes.
28 pub fn zeroes() Self {
29 return comptime Self.filled(0);
30 }
31
32 /// Sums all scalars in this vector.
33 pub fn sum(self: Self) Scalar {
34 var total: Scalar = 0;
35
36 comptime var i = 0;
37 inline while (i < N) : (i += 1) {
38 total += self.values[i];
39 }
40
41 return total;
42 }
43
44 /// Adds 2 vector together.
45 pub fn add(self: Self, other: Self) Self {
46 const left: @Vector(N, Scalar) = self.values;
47 const right: @Vector(N, Scalar) = other.values;
48
49 return .{ .values = left + right };
50 }
51
52 /// Adds another vector to this vector.
53 pub fn addAssign(self: *Self, other: Self) void {
54 const left: @Vector(N, Scalar) = self.values;
55 const right: @Vector(N, Scalar) = other.values;
56
57 self.values = left + right;
58 }
59
60 /// Subtracts 2 vector together.
61 pub fn sub(self: Self, other: Self) Self {
62 const left: @Vector(N, Scalar) = self.values;
63 const right: @Vector(N, Scalar) = other.values;
64
65 return .{ .values = left - right };
66 }
67
68 /// Adds another vector to this vector.
69 pub fn subAssign(self: *Self, other: Self) void {
70 const left: @Vector(N, Scalar) = self.values;
71 const right: @Vector(N, Scalar) = other.values;
72
73 self.values = left - right;
74 }
75
76 /// Multiplies 2 vectors together.
77 pub fn mul(self: Self, other: Self) Self {
78 const left: @Vector(N, Scalar) = self.values;
79 const right: @Vector(N, Scalar) = other.values;
80
81 return .{ .values = left * right };
82 }
83
84 /// Multiplies a vector and a scalar together.
85 pub fn mulScalar(self: Self, n: Scalar) Self {
86 const left: @Vector(N, Scalar) = self.values;
87 const right: @Vector(N, Scalar) = Self.filled(n).values;
88
89 return .{ .values = left * right };
90 }
91
92 /// Multiplies this vector with another vector.
93 pub fn mulAssign(self: *Self, other: Self) void {
94 const left: @Vector(N, Scalar) = self.values;
95 const right: @Vector(N, Scalar) = other.values;
96
97 self.values = left * right;
98 }
99
100 /// Multiplies this vector with a scalar.
101 pub fn mulAssignScalar(self: *Self, n: Scalar) void {
102 const left: @Vector(N, Scalar) = self.values;
103 const right: @Vector(N, Scalar) = Self.filled(n).values;
104
105 self.values = left * right;
106 }
107
108 /// Multiplies 2 vectors together.
109 pub fn div(self: Self, other: Self) Self {
110 const left: @Vector(N, Scalar) = self.values;
111 const right: @Vector(N, Scalar) = other.values;
112
113 return .{ .values = left / right };
114 }
115
116 /// Multiplies a vector and a scalar together.
117 pub fn divScalar(self: Self, n: Scalar) Self {
118 const left: @Vector(N, Scalar) = self.values;
119 const right: @Vector(N, Scalar) = Self.filled(n).values;
120
121 return .{ .values = left / right };
122 }
123
124 /// Multiplies this vector with another vector.
125 pub fn divAssign(self: *Self, other: Self) void {
126 const left: @Vector(N, Scalar) = self.values;
127 const right: @Vector(N, Scalar) = other.values;
128
129 self.values = left / right;
130 }
131
132 /// Multiplies this vector with a scalar.
133 pub fn divAssignScalar(self: *Self, n: Scalar) void {
134 const left: @Vector(N, Scalar) = self.values;
135 const right: @Vector(N, Scalar) = Self.filled(n).values;
136
137 self.values = left / right;
138 }
139
140 /// Calculates the dot product of 2 vectors.
141 pub fn dot(self: Self, other: Self) Scalar {
142 return self.mul(other).sum();
143 }
144
145 /// Calculates the norm squared of this vector.
146 pub fn normSquared(self: Self) Scalar {
147 return self.dot(self);
148 }
149
150 /// Calculates the norm of this vector.
151 pub fn norm(self: Self) Scalar {
152 return math.sqrt(self.normSquared());
153 }
154
155 /// Returns a normalized version of this vector.
156 pub fn normalize(self: Self) Self {
157 const values: @Vector(N, Scalar) = self.values;
158 const norms: @Vector(N, Scalar) = Self.filled(self.norm()).values;
159
160 return .{ .values = values / norms };
161 }
162
163 /// Make this vector normalized.
164 pub fn normalizeAssign(self: *Self) void {
165 const values: @Vector(N, Scalar) = self.values;
166 const norms: @Vector(N, Scalar) = Self.filled(self.norm()).values;
167
168 self.values = values / norms;
169 }
170
171 /// Calculates the cross product of 2 vectors.
172 pub fn cross(self: Self, other: Self) Self {
173 if (N != 3) {
174 @compileError("A cross product can only be calculated for a 3D vector.");
175 }
176
177 const values = [3]Scalar{
178 self.values[1] * other.values[2] - self.values[2] * other.values[1],
179 self.values[2] * other.values[0] - self.values[0] * other.values[2],
180 self.values[0] * other.values[1] - self.values[1] * other.values[0],
181 };
182
183 return Self{ .values = values };
184 }
185 };
186 }
187
188 fn expectVectorEqual(comptime N: usize, expected: Vector(N), actual: Vector(N)) void {
189 comptime var i = 0;
190 inline while (i < N) : (i += 1) {
191 std.testing.expectEqual(expected.values[i], actual.values[i]);
192 }
193 }
194
195 test "vector initialization" {
196 const actual = Vector(2).init(.{ 1, 2 });
197 std.testing.expectEqual(@floatCast(f32, 1), actual.values[0]);
198 std.testing.expectEqual(@floatCast(f32, 2), actual.values[1]);
199 }
200
201 test "vector scalar initialization" {
202 const v = Vector(3).filled(3);
203 expectVectorEqual(3, Vector(3).init(.{ 3, 3, 3 }), v);
204 }
205
206 test "vector zero initialization" {
207 const v = Vector(3).zeroes();
208 expectVectorEqual(3, Vector(3).init(.{ 0, 0, 0 }), v);
209 }
210
211 test "vector summation" {
212 const v = Vector(3).init(.{ 1, 2, 3 });
213 std.testing.expectEqual(@floatCast(f32, 6), v.sum());
214 }
215
216 test "vectors addition" {
217 const v1 = Vector(3).init(.{ 3, 4, 5 });
218 const v2 = Vector(3).init(.{ 6, 7, 8 });
219 expectVectorEqual(3, Vector(3).init(.{ 9, 11, 13 }), v1.add(v2));
220
221 var v3 = Vector(3).init(.{ 1, 2, 3 });
222 v3.addAssign(Vector(3).init(.{ 3, 2, 1 }));
223 expectVectorEqual(3, Vector(3).init(.{ 4, 4, 4 }), v3);
224 }
225
226 test "vectors subtraction" {
227 const v1 = Vector(3).init(.{ 3, 4, 5 });
228 const v2 = Vector(3).init(.{ 6, 7, 8 });
229 expectVectorEqual(3, Vector(3).init(.{ -3, -3, -3 }), v1.sub(v2));
230
231 var v3 = Vector(3).init(.{ 1, 2, 3 });
232 v3.subAssign(Vector(3).init(.{ 3, 2, 1 }));
233 expectVectorEqual(3, Vector(3).init(.{ -2, 0, 2 }), v3);
234 }
235
236 test "vector multiplication" {
237 const v1 = Vector(3).init(.{ 3, 4, 5 });
238 const v2 = Vector(3).init(.{ 6, 7, 8 });
239 expectVectorEqual(3, Vector(3).init(.{ 18, 28, 40 }), v1.mul(v2));
240
241 var v3 = Vector(3).init(.{ 1, 2, 3 });
242 v3.mulAssign(Vector(3).init(.{ 3, 2, 1 }));
243 expectVectorEqual(3, Vector(3).init(.{ 3, 4, 3 }), v3);
244 }
245
246 test "vector scalar multiplication" {
247 const v1 = Vector(3).init(.{ 3, 4, 5 });
248 expectVectorEqual(3, Vector(3).init(.{ 6, 8, 10 }), v1.mulScalar(2));
249
250 var v3 = Vector(3).init(.{ 1, 2, 3 });
251 v3.mulAssignScalar(3);
252 expectVectorEqual(3, Vector(3).init(.{ 3, 6, 9 }), v3);
253 }
254
255 test "vector division" {
256 const v1 = Vector(3).init(.{ 10, 20, 30 });
257 const v2 = Vector(3).init(.{ 5, 2, 6 });
258 expectVectorEqual(3, Vector(3).init(.{ 2, 10, 5 }), v1.div(v2));
259
260 var v3 = Vector(3).init(.{ 3, 2, 6 });
261 v3.divAssign(Vector(3).init(.{ 1, 2, 3 }));
262 expectVectorEqual(3, Vector(3).init(.{ 3, 1, 2 }), v3);
263 }
264
265 test "vector scalar division" {
266 const v1 = Vector(3).init(.{ 12, 24, 36 });
267 expectVectorEqual(3, Vector(3).init(.{ 1, 2, 3 }), v1.divScalar(12));
268
269 var v3 = Vector(3).init(.{ 1, 2, 3 });
270 v3.divAssignScalar(1);
271 expectVectorEqual(3, Vector(3).init(.{ 1, 2, 3 }), v3);
272 }
273
274 test "vector dot product" {
275 const v1 = Vector(3).init(.{ 1, 2, 3 });
276 const v2 = Vector(3).init(.{ 4, 5, 6 });
277 std.testing.expectEqual(@floatCast(f32, 32), v1.dot(v2));
278 }
279
280 test "vector norm squared" {
281 const v1 = Vector(2).init(.{ 3, 4 });
282 std.testing.expectEqual(@floatCast(f32, 25), v1.normSquared());
283 }
284
285 test "vector norm" {
286 const v1 = Vector(2).init(.{ 3, 4 });
287 std.testing.expectEqual(@floatCast(f32, 5), v1.norm());
288 }
289
290 test "vector normalization" {
291 const v1 = Vector(3).init(.{ 30, 10, 20 });
292 expectVectorEqual(3, Vector(3).init(.{0.80178372573729, 0.26726124191243, 0.53452248382486}), v1.normalize());
293
294 var v2 = Vector(3).init(.{ 60, 20, 40 });
295 v2.normalizeAssign();
296 expectVectorEqual(3, Vector(3).init(.{0.80178372573729, 0.26726124191243, 0.53452248382486}), v2);
297 }
298
299 test "vector cross product" {
300 const v1 = Vector(3).init(.{ 4, 5, 6 });
301 const v2 = Vector(3).init(.{ 7, 8, 9 });
302 expectVectorEqual(3, Vector(3).init(.{ -3, 6, -3 }), v1.cross(v2));
303 }