larb 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +14 -1
  4. data/ext/larb/color.c +446 -0
  5. data/ext/larb/color.h +35 -0
  6. data/ext/larb/extconf.rb +11 -0
  7. data/ext/larb/larb.c +27 -0
  8. data/ext/larb/larb.h +8 -0
  9. data/ext/larb/mat2.c +300 -0
  10. data/ext/larb/mat2.h +30 -0
  11. data/ext/larb/mat2d.c +380 -0
  12. data/ext/larb/mat2d.h +35 -0
  13. data/ext/larb/mat3.c +469 -0
  14. data/ext/larb/mat3.h +33 -0
  15. data/ext/larb/mat4.c +671 -0
  16. data/ext/larb/mat4.h +31 -0
  17. data/ext/larb/quat.c +523 -0
  18. data/ext/larb/quat.h +39 -0
  19. data/ext/larb/quat2.c +473 -0
  20. data/ext/larb/quat2.h +39 -0
  21. data/ext/larb/vec2.c +342 -0
  22. data/ext/larb/vec2.h +43 -0
  23. data/ext/larb/vec3.c +503 -0
  24. data/ext/larb/vec3.h +52 -0
  25. data/ext/larb/vec4.c +340 -0
  26. data/ext/larb/vec4.h +38 -0
  27. data/lib/larb/version.rb +5 -0
  28. data/lib/larb.rb +2 -14
  29. data/test/larb/color_test.rb +278 -0
  30. data/test/larb/mat2_test.rb +144 -0
  31. data/test/larb/mat2d_test.rb +172 -0
  32. data/test/larb/mat3_test.rb +147 -0
  33. data/test/larb/mat4_test.rb +270 -0
  34. data/test/larb/quat2_test.rb +161 -0
  35. data/test/larb/quat_test.rb +224 -0
  36. data/test/larb/vec2_test.rb +251 -0
  37. data/test/larb/vec3_test.rb +310 -0
  38. data/test/larb/vec4_test.rb +189 -0
  39. data/test/test_helper.rb +4 -0
  40. metadata +53 -14
  41. data/Rakefile +0 -11
  42. data/lib/larb/color.rb +0 -148
  43. data/lib/larb/mat2.rb +0 -119
  44. data/lib/larb/mat2d.rb +0 -180
  45. data/lib/larb/mat3.rb +0 -238
  46. data/lib/larb/mat4.rb +0 -329
  47. data/lib/larb/quat.rb +0 -238
  48. data/lib/larb/quat2.rb +0 -193
  49. data/lib/larb/vec2.rb +0 -150
  50. data/lib/larb/vec3.rb +0 -218
  51. data/lib/larb/vec4.rb +0 -125
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class Mat2Test < Test::Unit::TestCase
6
+ def test_new_identity_by_default
7
+ m = Larb::Mat2.new
8
+ assert_equal 1.0, m[0]
9
+ assert_equal 0.0, m[1]
10
+ assert_equal 0.0, m[2]
11
+ assert_equal 1.0, m[3]
12
+ end
13
+
14
+ def test_new_with_data
15
+ m = Larb::Mat2.new([1, 2, 3, 4])
16
+ assert_equal [1, 2, 3, 4], m.data
17
+ end
18
+
19
+ def test_identity
20
+ m = Larb::Mat2.identity
21
+ assert_equal 1.0, m[0]
22
+ assert_equal 1.0, m[3]
23
+ end
24
+
25
+ def test_zero
26
+ m = Larb::Mat2.zero
27
+ 4.times { |i| assert_equal 0.0, m[i] }
28
+ end
29
+
30
+ def test_rotation
31
+ m = Larb::Mat2.rotation(Math::PI / 2)
32
+ assert_in_delta 0.0, m[0], 1e-10
33
+ assert_in_delta 1.0, m[1], 1e-10
34
+ assert_in_delta(-1.0, m[2], 1e-10)
35
+ assert_in_delta 0.0, m[3], 1e-10
36
+ end
37
+
38
+ def test_scaling
39
+ m = Larb::Mat2.scaling(2, 3)
40
+ assert_equal 2.0, m[0]
41
+ assert_equal 3.0, m[3]
42
+ end
43
+
44
+ def test_from_vec2
45
+ v1 = Larb::Vec2.new(1, 2)
46
+ v2 = Larb::Vec2.new(3, 4)
47
+ m = Larb::Mat2.from_vec2(v1, v2)
48
+ assert_equal [1.0, 2.0, 3.0, 4.0], m.data
49
+ end
50
+
51
+ def test_multiply_mat2
52
+ m1 = Larb::Mat2.rotation(Math::PI / 4)
53
+ m2 = Larb::Mat2.rotation(Math::PI / 4)
54
+ result = m1 * m2
55
+ expected = Larb::Mat2.rotation(Math::PI / 2)
56
+ assert result.near?(expected)
57
+ end
58
+
59
+ def test_multiply_vec2
60
+ m = Larb::Mat2.rotation(Math::PI / 2)
61
+ v = Larb::Vec2.new(1, 0)
62
+ result = m * v
63
+ assert_in_delta 0.0, result.x, 1e-10
64
+ assert_in_delta 1.0, result.y, 1e-10
65
+ end
66
+
67
+ def test_multiply_scalar
68
+ m = Larb::Mat2.identity
69
+ result = m * 2
70
+ assert_equal 2.0, result[0]
71
+ assert_equal 2.0, result[3]
72
+ end
73
+
74
+ def test_add
75
+ m1 = Larb::Mat2.identity
76
+ m2 = Larb::Mat2.identity
77
+ result = m1 + m2
78
+ assert_equal 2.0, result[0]
79
+ end
80
+
81
+ def test_subtract
82
+ m1 = Larb::Mat2.identity
83
+ m2 = Larb::Mat2.identity
84
+ result = m1 - m2
85
+ assert_equal 0.0, result[0]
86
+ end
87
+
88
+ def test_determinant
89
+ m = Larb::Mat2.identity
90
+ assert_equal 1.0, m.determinant
91
+ end
92
+
93
+ def test_determinant_scaling
94
+ m = Larb::Mat2.scaling(2, 3)
95
+ assert_equal 6.0, m.determinant
96
+ end
97
+
98
+ def test_inverse
99
+ m = Larb::Mat2.scaling(2, 4)
100
+ inv = m.inverse
101
+ result = m * inv
102
+ assert result.near?(Larb::Mat2.identity)
103
+ end
104
+
105
+ def test_inverse_singular
106
+ m = Larb::Mat2.zero
107
+ assert_raise_message("Matrix is not invertible") { m.inverse }
108
+ end
109
+
110
+ def test_transpose
111
+ m = Larb::Mat2.new([1, 2, 3, 4])
112
+ result = m.transpose
113
+ assert_equal [1, 3, 2, 4], result.data
114
+ end
115
+
116
+ def test_adjoint
117
+ m = Larb::Mat2.new([1, 2, 3, 4])
118
+ adj = m.adjoint
119
+ assert_equal 4.0, adj[0]
120
+ assert_equal(-2.0, adj[1])
121
+ end
122
+
123
+ def test_frobenius_norm
124
+ m = Larb::Mat2.new([1, 2, 2, 0])
125
+ assert_equal 3.0, m.frobenius_norm
126
+ end
127
+
128
+ def test_equality
129
+ m1 = Larb::Mat2.identity
130
+ m2 = Larb::Mat2.identity
131
+ assert_equal m1, m2
132
+ end
133
+
134
+ def test_near
135
+ m1 = Larb::Mat2.identity
136
+ m2 = Larb::Mat2.new([1.0000001, 0, 0, 1.0000001])
137
+ assert m1.near?(m2)
138
+ end
139
+
140
+ def test_inspect
141
+ m = Larb::Mat2.identity
142
+ assert_match(/Mat2/, m.inspect)
143
+ end
144
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class Mat2dTest < Test::Unit::TestCase
6
+ def test_new_identity_by_default
7
+ m = Larb::Mat2d.new
8
+ assert_equal 1.0, m[0]
9
+ assert_equal 0.0, m[1]
10
+ assert_equal 0.0, m[2]
11
+ assert_equal 1.0, m[3]
12
+ assert_equal 0.0, m[4]
13
+ assert_equal 0.0, m[5]
14
+ end
15
+
16
+ def test_new_with_data
17
+ data = [1, 2, 3, 4, 5, 6]
18
+ m = Larb::Mat2d.new(data)
19
+ assert_equal [1, 2, 3, 4, 5, 6], m.data
20
+ end
21
+
22
+ def test_identity
23
+ m = Larb::Mat2d.identity
24
+ assert_equal 1.0, m[0]
25
+ assert_equal 1.0, m[3]
26
+ end
27
+
28
+ def test_zero
29
+ m = Larb::Mat2d.zero
30
+ 6.times { |i| assert_equal 0.0, m[i] }
31
+ end
32
+
33
+ def test_translation
34
+ m = Larb::Mat2d.translation(10, 20)
35
+ assert_equal 10.0, m[4]
36
+ assert_equal 20.0, m[5]
37
+ end
38
+
39
+ def test_rotation
40
+ m = Larb::Mat2d.rotation(Math::PI / 2)
41
+ assert_in_delta 0.0, m[0], 1e-10
42
+ assert_in_delta 1.0, m[1], 1e-10
43
+ end
44
+
45
+ def test_scaling
46
+ m = Larb::Mat2d.scaling(2, 3)
47
+ assert_equal 2.0, m[0]
48
+ assert_equal 3.0, m[3]
49
+ end
50
+
51
+ def test_from_rotation_translation_scale
52
+ m = Larb::Mat2d.from_rotation_translation_scale(
53
+ 0,
54
+ Larb::Vec2.new(10, 20),
55
+ Larb::Vec2.new(2, 3)
56
+ )
57
+ assert_equal 2.0, m[0]
58
+ assert_equal 3.0, m[3]
59
+ assert_equal 10.0, m[4]
60
+ assert_equal 20.0, m[5]
61
+ end
62
+
63
+ def test_multiply_mat2d
64
+ m1 = Larb::Mat2d.translation(10, 0)
65
+ m2 = Larb::Mat2d.translation(5, 0)
66
+ result = m1 * m2
67
+ assert_equal 15.0, result[4]
68
+ end
69
+
70
+ def test_multiply_vec2
71
+ m = Larb::Mat2d.translation(10, 20)
72
+ v = Larb::Vec2.new(0, 0)
73
+ result = m * v
74
+ assert_equal 10.0, result.x
75
+ assert_equal 20.0, result.y
76
+ end
77
+
78
+ def test_multiply_rotation_translation
79
+ m = Larb::Mat2d.rotation(Math::PI / 2) * Larb::Mat2d.translation(1, 0)
80
+ v = Larb::Vec2.new(0, 0)
81
+ result = m * v
82
+ assert_in_delta 0.0, result.x, 1e-10
83
+ assert_in_delta 1.0, result.y, 1e-10
84
+ end
85
+
86
+ def test_determinant
87
+ m = Larb::Mat2d.identity
88
+ assert_equal 1.0, m.determinant
89
+ end
90
+
91
+ def test_determinant_scaling
92
+ m = Larb::Mat2d.scaling(2, 3)
93
+ assert_equal 6.0, m.determinant
94
+ end
95
+
96
+ def test_inverse
97
+ m = Larb::Mat2d.translation(10, 20) * Larb::Mat2d.scaling(2, 2)
98
+ inv = m.inverse
99
+ result = m * inv
100
+ assert result.near?(Larb::Mat2d.identity)
101
+ end
102
+
103
+ def test_inverse_singular
104
+ m = Larb::Mat2d.zero
105
+ assert_raise_message("Matrix is not invertible") { m.inverse }
106
+ end
107
+
108
+ def test_translate
109
+ m = Larb::Mat2d.identity
110
+ result = m.translate(5, 10)
111
+ assert_equal 5.0, result[4]
112
+ assert_equal 10.0, result[5]
113
+ end
114
+
115
+ def test_rotate
116
+ m = Larb::Mat2d.identity
117
+ result = m.rotate(Math::PI / 2)
118
+ assert_in_delta 0.0, result[0], 1e-10
119
+ end
120
+
121
+ def test_scale
122
+ m = Larb::Mat2d.identity
123
+ result = m.scale(2, 3)
124
+ assert_equal 2.0, result[0]
125
+ assert_equal 3.0, result[3]
126
+ end
127
+
128
+ def test_extract_translation
129
+ m = Larb::Mat2d.translation(10, 20)
130
+ t = m.extract_translation
131
+ assert_equal 10.0, t.x
132
+ assert_equal 20.0, t.y
133
+ end
134
+
135
+ def test_extract_rotation
136
+ m = Larb::Mat2d.rotation(Math::PI / 4)
137
+ angle = m.extract_rotation
138
+ assert_in_delta Math::PI / 4, angle, 1e-10
139
+ end
140
+
141
+ def test_extract_scale
142
+ m = Larb::Mat2d.scaling(2, 3)
143
+ s = m.extract_scale
144
+ assert_in_delta 2.0, s.x, 1e-10
145
+ assert_in_delta 3.0, s.y, 1e-10
146
+ end
147
+
148
+ def test_to_mat3
149
+ m = Larb::Mat2d.translation(10, 20)
150
+ m3 = m.to_mat3
151
+ assert_instance_of Larb::Mat3, m3
152
+ assert_equal 10.0, m3[6]
153
+ assert_equal 20.0, m3[7]
154
+ end
155
+
156
+ def test_equality
157
+ m1 = Larb::Mat2d.identity
158
+ m2 = Larb::Mat2d.identity
159
+ assert_equal m1, m2
160
+ end
161
+
162
+ def test_near
163
+ m1 = Larb::Mat2d.identity
164
+ m2 = Larb::Mat2d.new([1.0000001, 0, 0, 1.0000001, 0, 0])
165
+ assert m1.near?(m2)
166
+ end
167
+
168
+ def test_inspect
169
+ m = Larb::Mat2d.identity
170
+ assert_match(/Mat2d/, m.inspect)
171
+ end
172
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class Mat3Test < Test::Unit::TestCase
6
+ def test_new_identity_by_default
7
+ m = Larb::Mat3.new
8
+ assert_equal 1.0, m[0]
9
+ assert_equal 1.0, m[4]
10
+ assert_equal 1.0, m[8]
11
+ end
12
+
13
+ def test_new_with_data
14
+ data = Array.new(9) { |i| i.to_f }
15
+ m = Larb::Mat3.new(data)
16
+ assert_equal data, m.data
17
+ end
18
+
19
+ def test_identity
20
+ m = Larb::Mat3.identity
21
+ assert_equal 1.0, m[0]
22
+ assert_equal 1.0, m[4]
23
+ assert_equal 1.0, m[8]
24
+ end
25
+
26
+ def test_zero
27
+ m = Larb::Mat3.zero
28
+ 9.times { |i| assert_equal 0.0, m[i] }
29
+ end
30
+
31
+ def test_from_mat4
32
+ m4 = Larb::Mat4.identity
33
+ m3 = Larb::Mat3.from_mat4(m4)
34
+ assert_equal 1.0, m3[0]
35
+ assert_equal 1.0, m3[4]
36
+ assert_equal 1.0, m3[8]
37
+ end
38
+
39
+ def test_from_quaternion
40
+ q = Larb::Quat.from_axis_angle(Larb::Vec3.new(0, 0, 1), Math::PI / 2)
41
+ m = Larb::Mat3.from_quaternion(q)
42
+ assert_in_delta 0.0, m[0], 1e-10
43
+ assert_in_delta 1.0, m[1], 1e-10
44
+ end
45
+
46
+ def test_translation
47
+ m = Larb::Mat3.translation(5, 10)
48
+ assert_equal 5.0, m[6]
49
+ assert_equal 10.0, m[7]
50
+ end
51
+
52
+ def test_rotation
53
+ m = Larb::Mat3.rotation(Math::PI / 2)
54
+ assert_in_delta 0.0, m[0], 1e-10
55
+ assert_in_delta 1.0, m[1], 1e-10
56
+ end
57
+
58
+ def test_scaling
59
+ m = Larb::Mat3.scaling(2, 3)
60
+ assert_equal 2.0, m[0]
61
+ assert_equal 3.0, m[4]
62
+ end
63
+
64
+ def test_multiply_mat3
65
+ m1 = Larb::Mat3.identity
66
+ m2 = Larb::Mat3.translation(1, 2)
67
+ result = m1 * m2
68
+ assert_equal 1.0, result[6]
69
+ assert_equal 2.0, result[7]
70
+ end
71
+
72
+ def test_multiply_vec3
73
+ m = Larb::Mat3.scaling(2, 3)
74
+ v = Larb::Vec3.new(1, 1, 1)
75
+ result = m * v
76
+ assert_equal 2.0, result.x
77
+ assert_equal 3.0, result.y
78
+ end
79
+
80
+ def test_determinant
81
+ m = Larb::Mat3.identity
82
+ assert_equal 1.0, m.determinant
83
+ end
84
+
85
+ def test_determinant_scaling
86
+ m = Larb::Mat3.scaling(2, 3)
87
+ assert_equal 6.0, m.determinant
88
+ end
89
+
90
+ def test_inverse
91
+ m = Larb::Mat3.scaling(2, 4)
92
+ inv = m.inverse
93
+ result = m * inv
94
+ assert result.near?(Larb::Mat3.identity)
95
+ end
96
+
97
+ def test_inverse_singular
98
+ m = Larb::Mat3.zero
99
+ assert_raise_message("Matrix is not invertible") { m.inverse }
100
+ end
101
+
102
+ def test_transpose
103
+ data = Array.new(9) { |i| i.to_f }
104
+ m = Larb::Mat3.new(data)
105
+ result = m.transpose
106
+ assert_equal 3.0, result[1]
107
+ assert_equal 1.0, result[3]
108
+ end
109
+
110
+ def test_translate
111
+ m = Larb::Mat3.identity
112
+ result = m.translate(5, 10)
113
+ assert_equal 5.0, result[6]
114
+ assert_equal 10.0, result[7]
115
+ end
116
+
117
+ def test_rotate
118
+ m = Larb::Mat3.identity
119
+ result = m.rotate(Math::PI / 2)
120
+ assert_in_delta 0.0, result[0], 1e-10
121
+ end
122
+
123
+ def test_scale
124
+ m = Larb::Mat3.identity
125
+ result = m.scale(2, 3)
126
+ assert_equal 2.0, result[0]
127
+ assert_equal 3.0, result[4]
128
+ end
129
+
130
+ def test_equality
131
+ m1 = Larb::Mat3.identity
132
+ m2 = Larb::Mat3.identity
133
+ assert_equal m1, m2
134
+ end
135
+
136
+ def test_near
137
+ m1 = Larb::Mat3.identity
138
+ m2 = Larb::Mat3.identity
139
+ m2[0] = 1.0000001
140
+ assert m1.near?(m2)
141
+ end
142
+
143
+ def test_inspect
144
+ m = Larb::Mat3.identity
145
+ assert_match(/Mat3/, m.inspect)
146
+ end
147
+ end
@@ -0,0 +1,270 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class Mat4Test < Test::Unit::TestCase
6
+ def test_new_identity_by_default
7
+ m = Larb::Mat4.new
8
+ assert_equal 1.0, m[0]
9
+ assert_equal 1.0, m[5]
10
+ assert_equal 1.0, m[10]
11
+ assert_equal 1.0, m[15]
12
+ assert_equal 0.0, m[1]
13
+ assert_equal 0.0, m[4]
14
+ end
15
+
16
+ def test_new_with_data
17
+ data = Array.new(16) { |i| i.to_f }
18
+ m = Larb::Mat4.new(data)
19
+ assert_equal data, m.data
20
+ end
21
+
22
+ def test_identity
23
+ m = Larb::Mat4.identity
24
+ assert_equal 1.0, m[0]
25
+ assert_equal 1.0, m[5]
26
+ assert_equal 1.0, m[10]
27
+ assert_equal 1.0, m[15]
28
+ end
29
+
30
+ def test_zero
31
+ m = Larb::Mat4.zero
32
+ 16.times { |i| assert_equal 0.0, m[i] }
33
+ end
34
+
35
+ def test_translation
36
+ m = Larb::Mat4.translation(1, 2, 3)
37
+ assert_equal 1.0, m[12]
38
+ assert_equal 2.0, m[13]
39
+ assert_equal 3.0, m[14]
40
+ assert_equal 1.0, m[0]
41
+ assert_equal 1.0, m[5]
42
+ assert_equal 1.0, m[10]
43
+ assert_equal 1.0, m[15]
44
+ end
45
+
46
+ def test_scaling
47
+ m = Larb::Mat4.scaling(2, 3, 4)
48
+ assert_equal 2.0, m[0]
49
+ assert_equal 3.0, m[5]
50
+ assert_equal 4.0, m[10]
51
+ assert_equal 1.0, m[15]
52
+ end
53
+
54
+ def test_rotation_x
55
+ m = Larb::Mat4.rotation_x(Math::PI / 2)
56
+ assert_equal 1.0, m[0]
57
+ assert_in_delta 0.0, m[5], 1e-10
58
+ assert_in_delta 1.0, m[6], 1e-10
59
+ assert_in_delta(-1.0, m[9], 1e-10)
60
+ assert_in_delta 0.0, m[10], 1e-10
61
+ end
62
+
63
+ def test_rotation_y
64
+ m = Larb::Mat4.rotation_y(Math::PI / 2)
65
+ assert_in_delta 0.0, m[0], 1e-10
66
+ assert_in_delta(-1.0, m[2], 1e-10)
67
+ assert_equal 1.0, m[5]
68
+ assert_in_delta 1.0, m[8], 1e-10
69
+ assert_in_delta 0.0, m[10], 1e-10
70
+ end
71
+
72
+ def test_rotation_z
73
+ m = Larb::Mat4.rotation_z(Math::PI / 2)
74
+ assert_in_delta 0.0, m[0], 1e-10
75
+ assert_in_delta 1.0, m[1], 1e-10
76
+ assert_in_delta(-1.0, m[4], 1e-10)
77
+ assert_in_delta 0.0, m[5], 1e-10
78
+ assert_equal 1.0, m[10]
79
+ end
80
+
81
+ def test_rotation
82
+ m = Larb::Mat4.rotation(Larb::Vec3.new(0, 1, 0), Math::PI / 2)
83
+ assert_in_delta 0.0, m[0], 1e-10
84
+ assert_in_delta 1.0, m[8], 1e-10
85
+ end
86
+
87
+ def test_look_at
88
+ eye = Larb::Vec3.new(0, 0, 5)
89
+ target = Larb::Vec3.new(0, 0, 0)
90
+ up = Larb::Vec3.new(0, 1, 0)
91
+ m = Larb::Mat4.look_at(eye, target, up)
92
+ assert_instance_of Larb::Mat4, m
93
+ assert_in_delta(-5.0, m[14], 1e-10)
94
+ end
95
+
96
+ def test_perspective
97
+ m = Larb::Mat4.perspective(Math::PI / 4, 16.0 / 9.0, 0.1, 100.0)
98
+ assert_instance_of Larb::Mat4, m
99
+ assert_equal(-1.0, m[11])
100
+ end
101
+
102
+ def test_orthographic
103
+ m = Larb::Mat4.orthographic(-1, 1, -1, 1, 0.1, 100)
104
+ assert_instance_of Larb::Mat4, m
105
+ assert_equal 1.0, m[0]
106
+ assert_equal 1.0, m[5]
107
+ end
108
+
109
+ def test_index_access
110
+ m = Larb::Mat4.identity
111
+ assert_equal 1.0, m[0]
112
+ assert_equal 0.0, m[1]
113
+ end
114
+
115
+ def test_index_assignment
116
+ m = Larb::Mat4.identity
117
+ m[0] = 5.0
118
+ assert_equal 5.0, m[0]
119
+ end
120
+
121
+ def test_multiply_mat4
122
+ m1 = Larb::Mat4.translation(1, 0, 0)
123
+ m2 = Larb::Mat4.translation(0, 1, 0)
124
+ result = m1 * m2
125
+ assert_equal 1.0, result[12]
126
+ assert_equal 1.0, result[13]
127
+ end
128
+
129
+ def test_multiply_identity
130
+ m = Larb::Mat4.translation(1, 2, 3)
131
+ result = Larb::Mat4.identity * m
132
+ assert_equal m.data, result.data
133
+ end
134
+
135
+ def test_multiply_vec4
136
+ m = Larb::Mat4.translation(1, 2, 3)
137
+ v = Larb::Vec4.new(0, 0, 0, 1)
138
+ result = m * v
139
+ assert_equal 1.0, result.x
140
+ assert_equal 2.0, result.y
141
+ assert_equal 3.0, result.z
142
+ assert_equal 1.0, result.w
143
+ end
144
+
145
+ def test_multiply_vec3
146
+ m = Larb::Mat4.translation(1, 2, 3)
147
+ v = Larb::Vec3.new(0, 0, 0)
148
+ result = m * v
149
+ assert_equal 1.0, result.x
150
+ assert_equal 2.0, result.y
151
+ assert_equal 3.0, result.z
152
+ end
153
+
154
+ def test_transpose
155
+ data = Array.new(16) { |i| i.to_f }
156
+ m = Larb::Mat4.new(data)
157
+ result = m.transpose
158
+ assert_equal 4.0, result[1]
159
+ assert_equal 1.0, result[4]
160
+ assert_equal 8.0, result[2]
161
+ assert_equal 2.0, result[8]
162
+ end
163
+
164
+ def test_inverse
165
+ m = Larb::Mat4.translation(1, 2, 3)
166
+ inv = m.inverse
167
+ result = m * inv
168
+ assert_in_delta 1.0, result[0], 1e-10
169
+ assert_in_delta 1.0, result[5], 1e-10
170
+ assert_in_delta 1.0, result[10], 1e-10
171
+ assert_in_delta 1.0, result[15], 1e-10
172
+ assert_in_delta 0.0, result[12], 1e-10
173
+ assert_in_delta 0.0, result[13], 1e-10
174
+ assert_in_delta 0.0, result[14], 1e-10
175
+ end
176
+
177
+ def test_inverse_singular
178
+ m = Larb::Mat4.zero
179
+ assert_raise_message("Matrix is not invertible") { m.inverse }
180
+ end
181
+
182
+ def test_to_a
183
+ m = Larb::Mat4.identity
184
+ arr = m.to_a
185
+ assert_equal m.data, arr
186
+ arr[0] = 999
187
+ assert_equal 1.0, m.data[0]
188
+ end
189
+
190
+ def test_determinant
191
+ m = Larb::Mat4.identity
192
+ assert_equal 1.0, m.determinant
193
+ end
194
+
195
+ def test_determinant_zero
196
+ m = Larb::Mat4.zero
197
+ assert_equal 0.0, m.determinant
198
+ end
199
+
200
+ def test_determinant_scaling
201
+ m = Larb::Mat4.scaling(2, 3, 4)
202
+ assert_equal 24.0, m.determinant
203
+ end
204
+
205
+ def test_add
206
+ m1 = Larb::Mat4.identity
207
+ m2 = Larb::Mat4.identity
208
+ result = m1 + m2
209
+ assert_equal 2.0, result[0]
210
+ assert_equal 2.0, result[5]
211
+ end
212
+
213
+ def test_subtract
214
+ m1 = Larb::Mat4.identity
215
+ m2 = Larb::Mat4.identity
216
+ result = m1 - m2
217
+ assert_equal 0.0, result[0]
218
+ assert_equal 0.0, result[5]
219
+ end
220
+
221
+ def test_equality
222
+ m1 = Larb::Mat4.identity
223
+ m2 = Larb::Mat4.identity
224
+ assert_equal m1, m2
225
+ end
226
+
227
+ def test_inequality
228
+ m1 = Larb::Mat4.identity
229
+ m2 = Larb::Mat4.translation(1, 0, 0)
230
+ assert_not_equal m1, m2
231
+ end
232
+
233
+ def test_near
234
+ m1 = Larb::Mat4.identity
235
+ m2 = Larb::Mat4.identity
236
+ m2[0] = 1.0000001
237
+ assert m1.near?(m2)
238
+ end
239
+
240
+ def test_extract_translation
241
+ m = Larb::Mat4.translation(1, 2, 3)
242
+ result = m.extract_translation
243
+ assert_equal Larb::Vec3.new(1, 2, 3), result
244
+ end
245
+
246
+ def test_extract_scale
247
+ m = Larb::Mat4.scaling(2, 3, 4)
248
+ result = m.extract_scale
249
+ assert_in_delta 2.0, result.x, 1e-10
250
+ assert_in_delta 3.0, result.y, 1e-10
251
+ assert_in_delta 4.0, result.z, 1e-10
252
+ end
253
+
254
+ def test_frustum
255
+ m = Larb::Mat4.frustum(-1, 1, -1, 1, 0.1, 100)
256
+ assert_instance_of Larb::Mat4, m
257
+ end
258
+
259
+ def test_from_quaternion
260
+ q = Larb::Quat.from_axis_angle(Larb::Vec3.new(0, 1, 0), Math::PI / 2)
261
+ m = Larb::Mat4.from_quaternion(q)
262
+ assert_instance_of Larb::Mat4, m
263
+ assert_in_delta 0.0, m[0], 1e-10
264
+ end
265
+
266
+ def test_inspect
267
+ m = Larb::Mat4.identity
268
+ assert_match(/Mat4/, m.inspect)
269
+ end
270
+ end