cyberarm_engine 0.25.0 → 0.30.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -8
  3. data/.rubocop.yml +7 -7
  4. data/.travis.yml +5 -5
  5. data/Gemfile +6 -6
  6. data/Gemfile.lock +37 -25
  7. data/LICENSE.txt +21 -21
  8. data/README.md +74 -74
  9. data/Rakefile +10 -10
  10. data/assets/shaders/fragment/g_buffer.glsl +30 -30
  11. data/assets/shaders/fragment/lighting.glsl +115 -115
  12. data/assets/shaders/include/light_struct.glsl +11 -11
  13. data/assets/shaders/include/material_struct.glsl +16 -16
  14. data/assets/shaders/vertex/g_buffer.glsl +28 -28
  15. data/assets/shaders/vertex/lighting.glsl +24 -24
  16. data/assets/textures/ui/circle.png +0 -0
  17. data/assets/textures/ui/circle_small.png +0 -0
  18. data/assets/textures/ui/rounded.png +0 -0
  19. data/assets/textures/ui/rounded_bottom.png +0 -0
  20. data/assets/textures/ui/rounded_left.png +0 -0
  21. data/assets/textures/ui/rounded_left_bottom.png +0 -0
  22. data/assets/textures/ui/rounded_left_top.png +0 -0
  23. data/assets/textures/ui/rounded_right.png +0 -0
  24. data/assets/textures/ui/rounded_right_bottom.png +0 -0
  25. data/assets/textures/ui/rounded_right_top.png +0 -0
  26. data/assets/textures/ui/rounded_small.png +0 -0
  27. data/assets/textures/ui/rounded_tiny.png +0 -0
  28. data/assets/textures/ui/rounded_top.png +0 -0
  29. data/assets/textures/ui/square.png +0 -0
  30. data/bin/console +14 -14
  31. data/bin/setup +8 -8
  32. data/cyberarm_engine.gemspec +35 -36
  33. data/lib/cyberarm_engine/animator.rb +219 -219
  34. data/lib/cyberarm_engine/background.rb +156 -158
  35. data/lib/cyberarm_engine/background_image.rb +93 -93
  36. data/lib/cyberarm_engine/background_nine_slice.rb +182 -142
  37. data/lib/cyberarm_engine/bounding_box.rb +150 -150
  38. data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
  39. data/lib/cyberarm_engine/cache/download_manager.rb +123 -123
  40. data/lib/cyberarm_engine/cache.rb +4 -4
  41. data/lib/cyberarm_engine/common.rb +133 -131
  42. data/lib/cyberarm_engine/config_file.rb +46 -46
  43. data/lib/cyberarm_engine/console/command.rb +157 -157
  44. data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
  45. data/lib/cyberarm_engine/console/subcommand.rb +99 -99
  46. data/lib/cyberarm_engine/console.rb +248 -248
  47. data/lib/cyberarm_engine/event_bus.rb +39 -0
  48. data/lib/cyberarm_engine/game_object.rb +244 -244
  49. data/lib/cyberarm_engine/game_state.rb +134 -124
  50. data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +111 -111
  51. data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +30 -30
  52. data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -17
  53. data/lib/cyberarm_engine/model/material.rb +21 -21
  54. data/lib/cyberarm_engine/model/mesh.rb +131 -131
  55. data/lib/cyberarm_engine/model/parser.rb +74 -74
  56. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
  57. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
  58. data/lib/cyberarm_engine/model.rb +216 -216
  59. data/lib/cyberarm_engine/model_cache.rb +31 -31
  60. data/lib/cyberarm_engine/notification.rb +82 -82
  61. data/lib/cyberarm_engine/notification_manager.rb +241 -241
  62. data/lib/cyberarm_engine/opengl/light.rb +52 -52
  63. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
  64. data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -41
  65. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
  66. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -167
  67. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -307
  68. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
  69. data/lib/cyberarm_engine/opengl/shader.rb +408 -408
  70. data/lib/cyberarm_engine/opengl/texture.rb +69 -69
  71. data/lib/cyberarm_engine/opengl.rb +53 -53
  72. data/lib/cyberarm_engine/pathfinding/graph.rb +64 -0
  73. data/lib/cyberarm_engine/pathfinding/graph_search.rb +6 -0
  74. data/lib/cyberarm_engine/pathfinding/graph_searches/astar_search.rb +6 -0
  75. data/lib/cyberarm_engine/pathfinding/graph_searches/breadth_first_search.rb +27 -0
  76. data/lib/cyberarm_engine/pathfinding/graph_searches/dijkstra_search.rb +6 -0
  77. data/lib/cyberarm_engine/pathfinding/graphs/grid.rb +52 -0
  78. data/lib/cyberarm_engine/ray.rb +56 -56
  79. data/lib/cyberarm_engine/result.rb +19 -0
  80. data/lib/cyberarm_engine/stats.rb +200 -200
  81. data/lib/cyberarm_engine/text.rb +288 -260
  82. data/lib/cyberarm_engine/timer.rb +27 -23
  83. data/lib/cyberarm_engine/transform.rb +296 -296
  84. data/lib/cyberarm_engine/trees/aabb_node.rb +126 -126
  85. data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -55
  86. data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -29
  87. data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
  88. data/lib/cyberarm_engine/ui/dialog.rb +24 -0
  89. data/lib/cyberarm_engine/ui/dsl.rb +170 -142
  90. data/lib/cyberarm_engine/ui/element.rb +664 -662
  91. data/lib/cyberarm_engine/ui/elements/button.rb +99 -100
  92. data/lib/cyberarm_engine/ui/elements/check_box.rb +58 -54
  93. data/lib/cyberarm_engine/ui/elements/container.rb +413 -407
  94. data/lib/cyberarm_engine/ui/elements/edit_box.rb +200 -179
  95. data/lib/cyberarm_engine/ui/elements/edit_line.rb +299 -297
  96. data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
  97. data/lib/cyberarm_engine/ui/elements/image.rb +78 -72
  98. data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
  99. data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
  100. data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
  101. data/lib/cyberarm_engine/ui/elements/progress.rb +95 -93
  102. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
  103. data/lib/cyberarm_engine/ui/elements/slider.rb +111 -107
  104. data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
  105. data/lib/cyberarm_engine/ui/elements/text_block.rb +236 -222
  106. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +71 -67
  107. data/lib/cyberarm_engine/ui/elements/widget.rb +45 -0
  108. data/lib/cyberarm_engine/ui/event.rb +54 -54
  109. data/lib/cyberarm_engine/ui/gui_state.rb +402 -326
  110. data/lib/cyberarm_engine/ui/page.rb +39 -0
  111. data/lib/cyberarm_engine/ui/style.rb +94 -61
  112. data/lib/cyberarm_engine/ui/theme.rb +237 -225
  113. data/lib/cyberarm_engine/vector.rb +312 -312
  114. data/lib/cyberarm_engine/version.rb +4 -4
  115. data/lib/cyberarm_engine/window.rb +234 -195
  116. data/lib/cyberarm_engine.rb +88 -76
  117. data/mrbgem.rake +29 -29
  118. metadata +30 -5
@@ -1,296 +1,296 @@
1
- module CyberarmEngine
2
- # Basic 4x4 matrix operations
3
- class Transform
4
- attr_reader :elements
5
-
6
- def initialize(matrix)
7
- @elements = matrix
8
-
9
- raise "Transform is wrong size! Got #{@elements.size}, expected 16" if 16 != @elements.size
10
- raise "Invalid value for matrix, must all be numeric!" if @elements.any? { |e| e.nil? || !e.is_a?(Numeric) }
11
- end
12
-
13
- def self.identity
14
- Transform.new(
15
- [
16
- 1, 0, 0, 0,
17
- 0, 1, 0, 0,
18
- 0, 0, 1, 0,
19
- 0, 0, 0, 1
20
- ]
21
- )
22
- end
23
-
24
- ### 2D Operations meant for interacting with Gosu ###
25
-
26
- # 2d rotate operation, replicates Gosu's Gosu.rotate function
27
- def self.rotate(angle, rotate_around = nil)
28
- double c = Math.cos(angle).degrees_to_radians
29
- double s = Math.sin(angle).degrees_to_radians
30
- matrix = [
31
- +c, +s, 0, 0,
32
- -s, +c, 0, 0,
33
- 0, 0, 1, 0,
34
- 0, 0, 0, 1
35
- ]
36
-
37
- rotate_matrix = Transform.new(matrix, rows: 4, columns: 4)
38
-
39
- if rotate_around && (rotate_around.x != 0.0 || rotate_around.y != 0.0)
40
- negative_rotate_around = Vector.new(-rotate_around.x, -rotate_around.y, -rotate_around.z)
41
-
42
- rotate_matrix = concat(
43
- concat(translate(negative_rotate_around), rotate_matrix),
44
- translate(rotate_around)
45
- )
46
- end
47
-
48
- rotate_matrix
49
- end
50
-
51
- # 2d translate operation, replicates Gosu's Gosu.translate function
52
- def self.translate(vector)
53
- x, y, z = vector.to_a[0..2]
54
- matrix = [
55
- 1, 0, 0, 0,
56
- 0, 1, 0, 0,
57
- 0, 0, 1, 0,
58
- x, y, z, 1
59
- ]
60
-
61
- Transform.new(matrix)
62
- end
63
-
64
- # 2d scale operation, replicates Gosu's Gosu.rotate function
65
- def self.scale(vector, center_around = nil)
66
- scale_x, scale_y, scale_z = vector.to_a[0..2]
67
- matrix = [
68
- scale_x, 0, 0, 0,
69
- 0, scale_y, 0, 0,
70
- 0, 0, scale_z, 0,
71
- 0, 0, 0, 1
72
- ]
73
-
74
- scale_matrix = Transform.new(matrix)
75
-
76
- if center_around && (center_around.x != 0.0 || center_around.y != 0.0)
77
- negative_center_around = Vector.new(-center_around.x, -center_around.y, -center_around.z)
78
-
79
- scale_matrix = concat(
80
- concat(translate(negative_center_around), scale_matrix),
81
- translate(center_around)
82
- )
83
- end
84
-
85
- scale_matrix
86
- end
87
-
88
- def self.concat(left, right)
89
- matrix = Array.new(left.elements.size)
90
- rows = 4
91
-
92
- matrix.size.times do |i|
93
- matrix[i] = 0
94
-
95
- rows.times do |j|
96
- matrix[i] += left.elements[i / rows * rows + j] * right.elements[i % rows + j * rows]
97
- end
98
- end
99
-
100
- Transform.new(matrix)
101
- end
102
-
103
- #### 3D Operations meant for OpenGL ###
104
-
105
- def self.translate_3d(vector)
106
- x, y, z = vector.to_a[0..2]
107
- matrix = [
108
- 1, 0, 0, x,
109
- 0, 1, 0, y,
110
- 0, 0, 1, z,
111
- 0, 0, 0, 1
112
- ]
113
-
114
- Transform.new(matrix)
115
- end
116
-
117
- def self.rotate_3d(vector, _order = "zyx")
118
- x, y, z = vector.to_a[0..2].map { |axis| axis * Math::PI / 180.0 }
119
-
120
- rotation_x = Transform.new(
121
- [
122
- 1, 0, 0, 0,
123
- 0, Math.cos(x), -Math.sin(x), 0,
124
- 0, Math.sin(x), Math.cos(x), 0,
125
- 0, 0, 0, 1
126
- ]
127
- )
128
-
129
- rotation_y = Transform.new(
130
- [
131
- Math.cos(y), 0, Math.sin(y), 0,
132
- 0, 1, 0, 0,
133
- -Math.sin(y), 0, Math.cos(y), 0,
134
- 0, 0, 0, 1
135
- ]
136
- )
137
-
138
- rotation_z = Transform.new(
139
- [
140
- Math.cos(z), -Math.sin(z), 0, 0,
141
- Math.sin(z), Math.cos(z), 0, 0,
142
- 0, 0, 1, 0,
143
- 0, 0, 0, 1
144
- ]
145
- )
146
-
147
- rotation_z * rotation_y * rotation_x
148
- end
149
-
150
- # Implements glRotatef
151
- # https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml
152
- def self.rotate_gl(angle, axis)
153
- radians = angle * Math::PI / 180.0
154
- s = Math.sin(radians)
155
- c = Math.cos(radians)
156
-
157
- axis = axis.normalized
158
- x, y, z = axis.to_a[0..2]
159
-
160
- n = (1.0 - c)
161
-
162
- Transform.new(
163
- [
164
- x * x * n + c, x * y * n - z * s, x * z * n + y * s, 0,
165
- y * x * n + z * s, y * y * n + c, y * z * n - x * s, 0,
166
- x * z * n - y * s, y * z * n + x * s, z * z * n + c, 0,
167
- 0, 0, 0, 1.0
168
- ]
169
- )
170
- end
171
-
172
- def self.scale_3d(vector)
173
- x, y, z = vector.to_a[0..2]
174
-
175
- Transform.new(
176
- [
177
- x, 0, 0, 0,
178
- 0, y, 0, 0,
179
- 0, 0, z, 0,
180
- 0, 0, 0, 1
181
- ]
182
- )
183
- end
184
-
185
- def self.perspective(fov_y, aspect_ratio, near, far)
186
- f = 1.0 / Math.tan(fov_y.degrees_to_radians / 2.0) # cotangent
187
- zn = (far + near.to_f) / (near - far.to_f)
188
- zf = (2.0 * far * near.to_f) / (near - far.to_f)
189
-
190
- Transform.new(
191
- [
192
- f / aspect_ratio, 0.0, 0.0, 0.0,
193
- 0.0, f, 0.0, 0.0,
194
- 0.0, 0.0, zn, zf,
195
- 0.0, 0.0, -1.0, 0.0
196
- ]
197
- )
198
- end
199
-
200
- def self.orthographic(left, right, bottom, top, near, far)
201
- s = Vector.new(
202
- 2 / (right - left.to_f),
203
- 2 / (top - bottom.to_f),
204
- -2 / (far - near.to_f)
205
- )
206
-
207
- t = Vector.new(
208
- (right + left.to_f) / (right - left.to_f),
209
- (top + bottom.to_f) / (top - bottom.to_f),
210
- (far + near.to_f) / (far - near.to_f)
211
- )
212
-
213
- Transform.new(
214
- [
215
- s.x, 0.0, 0.0, t.x,
216
- 0.0, s.y, 0.0, t.y,
217
- 0.0, 0.0, s.z, t.z,
218
- 0.0, 0.0, 0.0, 1.0
219
- ]
220
- )
221
- end
222
-
223
- def self.view(eye, orientation)
224
- # https://www.3dgep.com/understanding-the-view-matrix/#The_View_Matrix
225
- cosPitch = Math.cos(orientation.z * Math::PI / 180.0)
226
- sinPitch = Math.sin(orientation.z * Math::PI / 180.0)
227
- cosYaw = Math.cos(orientation.y * Math::PI / 180.0)
228
- sinYaw = Math.sin(orientation.y * Math::PI / 180.0)
229
-
230
- x_axis = Vector.new(cosYaw, 0, -sinYaw)
231
- y_axis = Vector.new(sinYaw * sinPitch, cosPitch, cosYaw * sinPitch)
232
- z_axis = Vector.new(sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw)
233
-
234
- Transform.new(
235
- [
236
- x_axis.x, y_axis.y, z_axis.z, 0,
237
- x_axis.x, y_axis.y, z_axis.z, 0,
238
- x_axis.x, y_axis.y, z_axis.z, 0,
239
- -x_axis.dot(eye), -y_axis.dot(eye), -z_axis.dot(eye), 1
240
- ]
241
- )
242
- end
243
-
244
- def *(other)
245
- case other
246
- when CyberarmEngine::Vector
247
- matrix = @elements.clone
248
- list = other.to_a
249
-
250
- @elements.each_with_index do |e, i|
251
- matrix[i] = e + list[i % 4]
252
- end
253
-
254
- Transform.new(matrix)
255
-
256
- when CyberarmEngine::Transform
257
- multiply_matrices(other)
258
- else
259
- p other.class
260
- raise TypeError, "Expected CyberarmEngine::Vector or CyberarmEngine::Transform got #{other.class}"
261
- end
262
- end
263
-
264
- def get(x, y)
265
- width = 4
266
-
267
- # puts "Transform|#{self.object_id} -> #{@elements[width * y + x].inspect} (index: #{width * y + x})"
268
- @elements[width * y + x]
269
- end
270
-
271
- def multiply_matrices(other)
272
- matrix = Array.new(16, 0)
273
-
274
- 4.times do |x|
275
- 4.times do |y|
276
- 4.times do |k|
277
- matrix[4 * y + x] += get(x, k) * other.get(k, y)
278
- end
279
- end
280
- end
281
-
282
- Transform.new(matrix)
283
- end
284
-
285
- # arranges Matrix in column major form
286
- def to_gl
287
- e = @elements
288
- [
289
- e[0], e[4], e[8], e[12],
290
- e[1], e[5], e[9], e[13],
291
- e[2], e[6], e[10], e[14],
292
- e[3], e[7], e[11], e[15]
293
- ]
294
- end
295
- end
296
- end
1
+ module CyberarmEngine
2
+ # Basic 4x4 matrix operations
3
+ class Transform
4
+ attr_reader :elements
5
+
6
+ def initialize(matrix)
7
+ @elements = matrix
8
+
9
+ raise "Transform is wrong size! Got #{@elements.size}, expected 16" if 16 != @elements.size
10
+ raise "Invalid value for matrix, must all be numeric!" if @elements.any? { |e| e.nil? || !e.is_a?(Numeric) }
11
+ end
12
+
13
+ def self.identity
14
+ Transform.new(
15
+ [
16
+ 1, 0, 0, 0,
17
+ 0, 1, 0, 0,
18
+ 0, 0, 1, 0,
19
+ 0, 0, 0, 1
20
+ ]
21
+ )
22
+ end
23
+
24
+ ### 2D Operations meant for interacting with Gosu ###
25
+
26
+ # 2d rotate operation, replicates Gosu's Gosu.rotate function
27
+ def self.rotate(angle, rotate_around = nil)
28
+ double c = Math.cos(angle).degrees_to_radians
29
+ double s = Math.sin(angle).degrees_to_radians
30
+ matrix = [
31
+ +c, +s, 0, 0,
32
+ -s, +c, 0, 0,
33
+ 0, 0, 1, 0,
34
+ 0, 0, 0, 1
35
+ ]
36
+
37
+ rotate_matrix = Transform.new(matrix, rows: 4, columns: 4)
38
+
39
+ if rotate_around && (rotate_around.x != 0.0 || rotate_around.y != 0.0)
40
+ negative_rotate_around = Vector.new(-rotate_around.x, -rotate_around.y, -rotate_around.z)
41
+
42
+ rotate_matrix = concat(
43
+ concat(translate(negative_rotate_around), rotate_matrix),
44
+ translate(rotate_around)
45
+ )
46
+ end
47
+
48
+ rotate_matrix
49
+ end
50
+
51
+ # 2d translate operation, replicates Gosu's Gosu.translate function
52
+ def self.translate(vector)
53
+ x, y, z = vector.to_a[0..2]
54
+ matrix = [
55
+ 1, 0, 0, 0,
56
+ 0, 1, 0, 0,
57
+ 0, 0, 1, 0,
58
+ x, y, z, 1
59
+ ]
60
+
61
+ Transform.new(matrix)
62
+ end
63
+
64
+ # 2d scale operation, replicates Gosu's Gosu.rotate function
65
+ def self.scale(vector, center_around = nil)
66
+ scale_x, scale_y, scale_z = vector.to_a[0..2]
67
+ matrix = [
68
+ scale_x, 0, 0, 0,
69
+ 0, scale_y, 0, 0,
70
+ 0, 0, scale_z, 0,
71
+ 0, 0, 0, 1
72
+ ]
73
+
74
+ scale_matrix = Transform.new(matrix)
75
+
76
+ if center_around && (center_around.x != 0.0 || center_around.y != 0.0)
77
+ negative_center_around = Vector.new(-center_around.x, -center_around.y, -center_around.z)
78
+
79
+ scale_matrix = concat(
80
+ concat(translate(negative_center_around), scale_matrix),
81
+ translate(center_around)
82
+ )
83
+ end
84
+
85
+ scale_matrix
86
+ end
87
+
88
+ def self.concat(left, right)
89
+ matrix = Array.new(left.elements.size)
90
+ rows = 4
91
+
92
+ matrix.size.times do |i|
93
+ matrix[i] = 0
94
+
95
+ rows.times do |j|
96
+ matrix[i] += left.elements[i / rows * rows + j] * right.elements[i % rows + j * rows]
97
+ end
98
+ end
99
+
100
+ Transform.new(matrix)
101
+ end
102
+
103
+ #### 3D Operations meant for OpenGL ###
104
+
105
+ def self.translate_3d(vector)
106
+ x, y, z = vector.to_a[0..2]
107
+ matrix = [
108
+ 1, 0, 0, x,
109
+ 0, 1, 0, y,
110
+ 0, 0, 1, z,
111
+ 0, 0, 0, 1
112
+ ]
113
+
114
+ Transform.new(matrix)
115
+ end
116
+
117
+ def self.rotate_3d(vector, _order = "zyx")
118
+ x, y, z = vector.to_a[0..2].map { |axis| axis * Math::PI / 180.0 }
119
+
120
+ rotation_x = Transform.new(
121
+ [
122
+ 1, 0, 0, 0,
123
+ 0, Math.cos(x), -Math.sin(x), 0,
124
+ 0, Math.sin(x), Math.cos(x), 0,
125
+ 0, 0, 0, 1
126
+ ]
127
+ )
128
+
129
+ rotation_y = Transform.new(
130
+ [
131
+ Math.cos(y), 0, Math.sin(y), 0,
132
+ 0, 1, 0, 0,
133
+ -Math.sin(y), 0, Math.cos(y), 0,
134
+ 0, 0, 0, 1
135
+ ]
136
+ )
137
+
138
+ rotation_z = Transform.new(
139
+ [
140
+ Math.cos(z), -Math.sin(z), 0, 0,
141
+ Math.sin(z), Math.cos(z), 0, 0,
142
+ 0, 0, 1, 0,
143
+ 0, 0, 0, 1
144
+ ]
145
+ )
146
+
147
+ rotation_z * rotation_y * rotation_x
148
+ end
149
+
150
+ # Implements glRotatef
151
+ # https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml
152
+ def self.rotate_gl(angle, axis)
153
+ radians = angle * Math::PI / 180.0
154
+ s = Math.sin(radians)
155
+ c = Math.cos(radians)
156
+
157
+ axis = axis.normalized
158
+ x, y, z = axis.to_a[0..2]
159
+
160
+ n = (1.0 - c)
161
+
162
+ Transform.new(
163
+ [
164
+ x * x * n + c, x * y * n - z * s, x * z * n + y * s, 0,
165
+ y * x * n + z * s, y * y * n + c, y * z * n - x * s, 0,
166
+ x * z * n - y * s, y * z * n + x * s, z * z * n + c, 0,
167
+ 0, 0, 0, 1.0
168
+ ]
169
+ )
170
+ end
171
+
172
+ def self.scale_3d(vector)
173
+ x, y, z = vector.to_a[0..2]
174
+
175
+ Transform.new(
176
+ [
177
+ x, 0, 0, 0,
178
+ 0, y, 0, 0,
179
+ 0, 0, z, 0,
180
+ 0, 0, 0, 1
181
+ ]
182
+ )
183
+ end
184
+
185
+ def self.perspective(fov_y, aspect_ratio, near, far)
186
+ f = 1.0 / Math.tan(fov_y.degrees_to_radians / 2.0) # cotangent
187
+ zn = (far + near.to_f) / (near - far.to_f)
188
+ zf = (2.0 * far * near.to_f) / (near - far.to_f)
189
+
190
+ Transform.new(
191
+ [
192
+ f / aspect_ratio, 0.0, 0.0, 0.0,
193
+ 0.0, f, 0.0, 0.0,
194
+ 0.0, 0.0, zn, zf,
195
+ 0.0, 0.0, -1.0, 0.0
196
+ ]
197
+ )
198
+ end
199
+
200
+ def self.orthographic(left, right, bottom, top, near, far)
201
+ s = Vector.new(
202
+ 2 / (right - left.to_f),
203
+ 2 / (top - bottom.to_f),
204
+ -2 / (far - near.to_f)
205
+ )
206
+
207
+ t = Vector.new(
208
+ (right + left.to_f) / (right - left.to_f),
209
+ (top + bottom.to_f) / (top - bottom.to_f),
210
+ (far + near.to_f) / (far - near.to_f)
211
+ )
212
+
213
+ Transform.new(
214
+ [
215
+ s.x, 0.0, 0.0, t.x,
216
+ 0.0, s.y, 0.0, t.y,
217
+ 0.0, 0.0, s.z, t.z,
218
+ 0.0, 0.0, 0.0, 1.0
219
+ ]
220
+ )
221
+ end
222
+
223
+ def self.view(eye, orientation)
224
+ # https://www.3dgep.com/understanding-the-view-matrix/#The_View_Matrix
225
+ cosPitch = Math.cos(orientation.z * Math::PI / 180.0)
226
+ sinPitch = Math.sin(orientation.z * Math::PI / 180.0)
227
+ cosYaw = Math.cos(orientation.y * Math::PI / 180.0)
228
+ sinYaw = Math.sin(orientation.y * Math::PI / 180.0)
229
+
230
+ x_axis = Vector.new(cosYaw, 0, -sinYaw)
231
+ y_axis = Vector.new(sinYaw * sinPitch, cosPitch, cosYaw * sinPitch)
232
+ z_axis = Vector.new(sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw)
233
+
234
+ Transform.new(
235
+ [
236
+ x_axis.x, y_axis.y, z_axis.z, 0,
237
+ x_axis.x, y_axis.y, z_axis.z, 0,
238
+ x_axis.x, y_axis.y, z_axis.z, 0,
239
+ -x_axis.dot(eye), -y_axis.dot(eye), -z_axis.dot(eye), 1
240
+ ]
241
+ )
242
+ end
243
+
244
+ def *(other)
245
+ case other
246
+ when CyberarmEngine::Vector
247
+ matrix = @elements.clone
248
+ list = other.to_a
249
+
250
+ @elements.each_with_index do |e, i|
251
+ matrix[i] = e + list[i % 4]
252
+ end
253
+
254
+ Transform.new(matrix)
255
+
256
+ when CyberarmEngine::Transform
257
+ multiply_matrices(other)
258
+ else
259
+ p other.class
260
+ raise TypeError, "Expected CyberarmEngine::Vector or CyberarmEngine::Transform got #{other.class}"
261
+ end
262
+ end
263
+
264
+ def get(x, y)
265
+ width = 4
266
+
267
+ # puts "Transform|#{self.object_id} -> #{@elements[width * y + x].inspect} (index: #{width * y + x})"
268
+ @elements[width * y + x]
269
+ end
270
+
271
+ def multiply_matrices(other)
272
+ matrix = Array.new(16, 0)
273
+
274
+ 4.times do |x|
275
+ 4.times do |y|
276
+ 4.times do |k|
277
+ matrix[4 * y + x] += get(x, k) * other.get(k, y)
278
+ end
279
+ end
280
+ end
281
+
282
+ Transform.new(matrix)
283
+ end
284
+
285
+ # arranges Matrix in column major form
286
+ def to_gl
287
+ e = @elements
288
+ [
289
+ e[0], e[4], e[8], e[12],
290
+ e[1], e[5], e[9], e[13],
291
+ e[2], e[6], e[10], e[14],
292
+ e[3], e[7], e[11], e[15]
293
+ ]
294
+ end
295
+ end
296
+ end