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,69 +1,69 @@
1
- module CyberarmEngine
2
- class Texture
3
- DEFAULT_TEXTURE = "#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/default.png".freeze
4
-
5
- CACHE = {}
6
-
7
- def self.release_textures
8
- CACHE.values.each do |id|
9
- glDeleteTextures(id)
10
- end
11
- end
12
-
13
- def self.from_cache(path, retro)
14
- CACHE.dig("#{path}?retro=#{retro}")
15
- end
16
-
17
- attr_reader :id
18
-
19
- def initialize(path: nil, image: nil, retro: false)
20
- raise "keyword :path or :image must be provided!" if path.nil? && image.nil?
21
-
22
- @retro = retro
23
- @path = path
24
-
25
- if @path
26
- unless File.exist?(@path)
27
- warn "Missing texture at: #{@path}"
28
- @retro = true # override retro setting
29
- @path = DEFAULT_TEXTURE
30
- end
31
-
32
- if texture = Texture.from_cache(@path, @retro)
33
- @id = texture.id
34
- return
35
- end
36
-
37
- image = load_image(@path)
38
- @id = create_from_image(image)
39
- else
40
- @id = create_from_image(image)
41
- end
42
- end
43
-
44
- def load_image(path)
45
- CACHE["#{path}?retro=#{@retro}"] = self
46
- Gosu::Image.new(path, retro: @retro)
47
- end
48
-
49
- def create_from_image(image)
50
- array_of_pixels = image.to_blob
51
-
52
- tex_names_buf = " " * 4
53
- glGenTextures(1, tex_names_buf)
54
- texture_id = tex_names_buf.unpack1("L2")
55
-
56
- glBindTexture(GL_TEXTURE_2D, texture_id)
57
- glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array_of_pixels)
58
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
59
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
60
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) if @retro
61
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) unless @retro
62
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
63
- glGenerateMipmap(GL_TEXTURE_2D)
64
- gl_error?
65
-
66
- texture_id
67
- end
68
- end
69
- end
1
+ module CyberarmEngine
2
+ class Texture
3
+ DEFAULT_TEXTURE = "#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/default.png".freeze
4
+
5
+ CACHE = {}
6
+
7
+ def self.release_textures
8
+ CACHE.values.each do |id|
9
+ glDeleteTextures(id)
10
+ end
11
+ end
12
+
13
+ def self.from_cache(path, retro)
14
+ CACHE.dig("#{path}?retro=#{retro}")
15
+ end
16
+
17
+ attr_reader :id
18
+
19
+ def initialize(path: nil, image: nil, retro: false)
20
+ raise "keyword :path or :image must be provided!" if path.nil? && image.nil?
21
+
22
+ @retro = retro
23
+ @path = path
24
+
25
+ if @path
26
+ unless File.exist?(@path)
27
+ warn "Missing texture at: #{@path}"
28
+ @retro = true # override retro setting
29
+ @path = DEFAULT_TEXTURE
30
+ end
31
+
32
+ if texture = Texture.from_cache(@path, @retro)
33
+ @id = texture.id
34
+ return
35
+ end
36
+
37
+ image = load_image(@path)
38
+ @id = create_from_image(image)
39
+ else
40
+ @id = create_from_image(image)
41
+ end
42
+ end
43
+
44
+ def load_image(path)
45
+ CACHE["#{path}?retro=#{@retro}"] = self
46
+ Gosu::Image.new(path, retro: @retro)
47
+ end
48
+
49
+ def create_from_image(image)
50
+ array_of_pixels = image.to_blob
51
+
52
+ tex_names_buf = " " * 4
53
+ glGenTextures(1, tex_names_buf)
54
+ texture_id = tex_names_buf.unpack1("L2")
55
+
56
+ glBindTexture(GL_TEXTURE_2D, texture_id)
57
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array_of_pixels)
58
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
59
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
60
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) if @retro
61
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) unless @retro
62
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
63
+ glGenerateMipmap(GL_TEXTURE_2D)
64
+ gl_error?
65
+
66
+ texture_id
67
+ end
68
+ end
69
+ end
@@ -1,53 +1,53 @@
1
- begin
2
- require "opengl"
3
- require "glu"
4
- rescue LoadError
5
- puts "Required gem is not installed, please install 'opengl-bindings' and try again."
6
- exit(1)
7
- end
8
-
9
- module CyberarmEngine
10
- def gl_error?
11
- e = glGetError
12
- if e != OpenGL::GL_NO_ERROR
13
- warn "OpenGL error detected by handler at: #{caller[0]}"
14
- warn " #{gluErrorString(e)} (#{e})\n"
15
- exit if Window.instance&.exit_on_opengl_error?
16
- end
17
- end
18
-
19
- def preload_default_shaders
20
- shaders = %w[g_buffer lighting]
21
- shaders.each do |shader|
22
- Shader.new(
23
- name: shader,
24
- includes_dir: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/include",
25
- vertex: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/vertex/#{shader}.glsl",
26
- fragment: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/fragment/#{shader}.glsl"
27
- )
28
- end
29
- end
30
- end
31
-
32
- require_relative "opengl/shader"
33
- require_relative "opengl/texture"
34
- require_relative "opengl/light"
35
- require_relative "opengl/perspective_camera"
36
- require_relative "opengl/orthographic_camera"
37
-
38
- require_relative "opengl/renderer/g_buffer"
39
- require_relative "opengl/renderer/bounding_box_renderer"
40
- require_relative "opengl/renderer/opengl_renderer"
41
- require_relative "opengl/renderer/renderer"
42
-
43
- require_relative "trees/aabb_tree_debug"
44
- require_relative "trees/aabb_node"
45
- require_relative "trees/aabb_tree"
46
-
47
- require_relative "model"
48
- require_relative "model_cache"
49
- require_relative "model/material"
50
- require_relative "model/mesh"
51
- require_relative "model/parser"
52
- require_relative "model/parsers/wavefront_parser"
53
- require_relative "model/parsers/collada_parser" if RUBY_ENGINE != "mruby" && defined?(Nokogiri)
1
+ begin
2
+ require "opengl"
3
+ require "glu"
4
+ rescue LoadError
5
+ puts "Required gem is not installed, please install 'opengl-bindings' and try again."
6
+ exit(1)
7
+ end
8
+
9
+ module CyberarmEngine
10
+ def gl_error?
11
+ e = glGetError
12
+ if e != OpenGL::GL_NO_ERROR
13
+ warn "OpenGL error detected by handler at: #{caller[0]}"
14
+ warn " #{gluErrorString(e)} (#{e})\n"
15
+ exit if Window.instance&.exit_on_opengl_error?
16
+ end
17
+ end
18
+
19
+ def preload_default_shaders
20
+ shaders = %w[g_buffer lighting]
21
+ shaders.each do |shader|
22
+ Shader.new(
23
+ name: shader,
24
+ includes_dir: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/include",
25
+ vertex: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/vertex/#{shader}.glsl",
26
+ fragment: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/fragment/#{shader}.glsl"
27
+ )
28
+ end
29
+ end
30
+ end
31
+
32
+ require_relative "opengl/shader"
33
+ require_relative "opengl/texture"
34
+ require_relative "opengl/light"
35
+ require_relative "opengl/perspective_camera"
36
+ require_relative "opengl/orthographic_camera"
37
+
38
+ require_relative "opengl/renderer/g_buffer"
39
+ require_relative "opengl/renderer/bounding_box_renderer"
40
+ require_relative "opengl/renderer/opengl_renderer"
41
+ require_relative "opengl/renderer/renderer"
42
+
43
+ require_relative "trees/aabb_tree_debug"
44
+ require_relative "trees/aabb_node"
45
+ require_relative "trees/aabb_tree"
46
+
47
+ require_relative "model"
48
+ require_relative "model_cache"
49
+ require_relative "model/material"
50
+ require_relative "model/mesh"
51
+ require_relative "model/parser"
52
+ require_relative "model/parsers/wavefront_parser"
53
+ require_relative "model/parsers/collada_parser" if RUBY_ENGINE != "mruby" && defined?(Nokogiri)
@@ -0,0 +1,64 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class Graph
4
+ class Node
5
+ KEY_FORMAT = "%s:%s:%s".freeze
6
+
7
+ attr_reader :x, :y, :z, :cost, :key, :edge_nodes
8
+
9
+ def initialize(x:, y:, z: 0, cost: 0)
10
+ @x = x
11
+ @y = y
12
+ @z = z
13
+ @cost = cost
14
+
15
+ @key = format(KEY_FORMAT, @x, @y, @z).freeze
16
+
17
+ @edge_nodes = []
18
+ end
19
+
20
+ def add_edge_node(node)
21
+ index = @edge_nodes.find_index { |n| n.key == node.key }
22
+
23
+ return if index
24
+
25
+ @edge_nodes.push(node)
26
+ end
27
+
28
+ def remove_edge_node(node)
29
+ index = @edge_nodes.find_index { |n| n.key == node.key }
30
+
31
+ return unless index
32
+
33
+ @edge_nodes.delete(index)
34
+ end
35
+
36
+ def inspect
37
+ format "#<%<class>s:%<id>#018x @key=%<key>s @cost=%<cost>s @edge_nodes=%<edge_nodes>s>",
38
+ class: self.class,
39
+ id: object_id << 1,
40
+ key: key.inspect,
41
+ cost: cost.inspect,
42
+ edge_nodes: edge_nodes.map { |n| n&.key }
43
+ end
44
+ end
45
+
46
+ def initialize(nodes: {})
47
+ @nodes = nodes
48
+ end
49
+
50
+ def node(key)
51
+ @nodes[key]
52
+ end
53
+
54
+ def node_at(x, y, z = 0)
55
+ key = format(Node::KEY_FORMAT, x, y, z)
56
+ @nodes[key]
57
+ end
58
+
59
+ def neighbors(node)
60
+ node.edge_nodes
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,6 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class GraphSearch
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class AStarSearch < GraphSearch
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,27 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class BreadthFirstSearch < GraphSearch
4
+ def self.search(graph:, start:, goal: nil)
5
+ frontier = []
6
+ came_from = {}
7
+
8
+ frontier.push(start)
9
+ came_from[start.key] = start
10
+
11
+ while(current = frontier.shift)
12
+ # early exit if we reach our goal
13
+ break if current == goal
14
+
15
+ graph.neighbors(current).each do |neighbor|
16
+ next if came_from[neighbor.key]
17
+
18
+ frontier.push(neighbor)
19
+ came_from[neighbor.key] = current
20
+ end
21
+ end
22
+
23
+ came_from
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class DijkstraSearch < GraphSearch
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,52 @@
1
+ module CyberarmEngine
2
+ module Pathfinding
3
+ class Grid < Graph
4
+ def add_node(x:, y:, z: 0, cost: 0, replace: false)
5
+ key = format(Node::KEY_FORMAT, x, y, z)
6
+ node = @nodes[key]
7
+
8
+ raise "Node at: #{key} already exists! (#{node})" if node && !replace
9
+
10
+ node = Node.new(x: x, y: y, z: z, cost: cost)
11
+ @nodes[key] = node
12
+
13
+ update_node_edge_nodes(node)
14
+ node
15
+ end
16
+
17
+ def remove_node(node)
18
+ update_node_edge_nodes(node, remove_node: true)
19
+
20
+ @nodes.delete(node.key)
21
+ end
22
+
23
+ def update_node_edge_nodes(node, remove_node: false)
24
+ x = node.x
25
+ y = node.y
26
+ z = node.z
27
+
28
+ # add node to neighbors
29
+ # 2D
30
+ left = @nodes[format(Node::KEY_FORMAT, x - 1, y, z)]
31
+ right = @nodes[format(Node::KEY_FORMAT, x + 1, y, z)]
32
+ top = @nodes[format(Node::KEY_FORMAT, x, y - 1, z)]
33
+ bottom = @nodes[format(Node::KEY_FORMAT, x, y + 1, z)]
34
+ # 3D
35
+ front = @nodes[format(Node::KEY_FORMAT, x, y, z - 1)]
36
+ back = @nodes[format(Node::KEY_FORMAT, x, y, z + 1)]
37
+
38
+ possible_edge_nodes = [left, right, top, bottom, front, back]
39
+
40
+ if remove_node
41
+ possible_edge_nodes.each { |n| n&.remove_edge_node(node) }
42
+ else
43
+ possible_edge_nodes.each { |n| n&.add_edge_node(node) }
44
+ end
45
+ end
46
+
47
+ def update_edge_nodes
48
+ @nodes.each { |k, n| update_node_edge_nodes(n) }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,56 +1,56 @@
1
- module CyberarmEngine
2
- class Ray
3
- def initialize(origin, direction, range = Float::INFINITY)
4
- raise "Origin must be a Vector!" unless origin.is_a?(Vector)
5
- raise "Direction must be a Vector!" unless direction.is_a?(Vector)
6
-
7
- @origin = origin
8
- @direction = direction
9
- @range = range
10
-
11
- @inverse_direction = @direction.inverse
12
- end
13
-
14
- def intersect?(intersectable)
15
- if intersectable.is_a?(BoundingBox)
16
- intersect_bounding_box?(intersectable)
17
- else
18
- raise NotImplementedError, "Ray intersection test for #{intersectable.class} not implemented."
19
- end
20
- end
21
-
22
- # Based on: https://tavianator.com/fast-branchless-raybounding-box-intersections/
23
- def intersect_bounding_box?(box)
24
- tmin = -@range
25
- tmax = @range
26
-
27
- tx1 = (box.min.x - @origin.x) * @inverse_direction.x
28
- tx2 = (box.max.x - @origin.x) * @inverse_direction.x
29
-
30
- tmin = max(tmin, min(tx1, tx2))
31
- tmax = min(tmax, max(tx1, tx2))
32
-
33
- ty1 = (box.min.y - @origin.y) * @inverse_direction.y
34
- ty2 = (box.max.y - @origin.y) * @inverse_direction.y
35
-
36
- tmin = max(tmin, min(ty1, ty2))
37
- tmax = min(tmax, max(ty1, ty2))
38
-
39
- tz1 = (box.min.z - @origin.z) * @inverse_direction.z
40
- tz2 = (box.max.z - @origin.z) * @inverse_direction.z
41
-
42
- tmin = max(tmin, min(tz1, tz2))
43
- tmax = min(tmax, max(tz1, tz2))
44
-
45
- tmax >= max(tmin, 0.0)
46
- end
47
-
48
- def min(x, y)
49
- ((x) < (y) ? x : y)
50
- end
51
-
52
- def max(x, y)
53
- ((x) > (y) ? x : y)
54
- end
55
- end
56
- end
1
+ module CyberarmEngine
2
+ class Ray
3
+ def initialize(origin, direction, range = Float::INFINITY)
4
+ raise "Origin must be a Vector!" unless origin.is_a?(Vector)
5
+ raise "Direction must be a Vector!" unless direction.is_a?(Vector)
6
+
7
+ @origin = origin
8
+ @direction = direction
9
+ @range = range
10
+
11
+ @inverse_direction = @direction.inverse
12
+ end
13
+
14
+ def intersect?(intersectable)
15
+ if intersectable.is_a?(BoundingBox)
16
+ intersect_bounding_box?(intersectable)
17
+ else
18
+ raise NotImplementedError, "Ray intersection test for #{intersectable.class} not implemented."
19
+ end
20
+ end
21
+
22
+ # Based on: https://tavianator.com/fast-branchless-raybounding-box-intersections/
23
+ def intersect_bounding_box?(box)
24
+ tmin = -@range
25
+ tmax = @range
26
+
27
+ tx1 = (box.min.x - @origin.x) * @inverse_direction.x
28
+ tx2 = (box.max.x - @origin.x) * @inverse_direction.x
29
+
30
+ tmin = max(tmin, min(tx1, tx2))
31
+ tmax = min(tmax, max(tx1, tx2))
32
+
33
+ ty1 = (box.min.y - @origin.y) * @inverse_direction.y
34
+ ty2 = (box.max.y - @origin.y) * @inverse_direction.y
35
+
36
+ tmin = max(tmin, min(ty1, ty2))
37
+ tmax = min(tmax, max(ty1, ty2))
38
+
39
+ tz1 = (box.min.z - @origin.z) * @inverse_direction.z
40
+ tz2 = (box.max.z - @origin.z) * @inverse_direction.z
41
+
42
+ tmin = max(tmin, min(tz1, tz2))
43
+ tmax = min(tmax, max(tz1, tz2))
44
+
45
+ tmax >= max(tmin, 0.0)
46
+ end
47
+
48
+ def min(x, y)
49
+ ((x) < (y) ? x : y)
50
+ end
51
+
52
+ def max(x, y)
53
+ ((x) > (y) ? x : y)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ module CyberarmEngine
2
+ # result pattern
3
+ class Result
4
+ attr_accessor :error, :data
5
+
6
+ def initialize(data: nil, error: nil)
7
+ @data = data
8
+ @error = error
9
+ end
10
+
11
+ def okay?
12
+ !error?
13
+ end
14
+
15
+ def error?
16
+ @error || @data.nil?
17
+ end
18
+ end
19
+ end