cyberarm_engine 0.13.1 → 0.17.1

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile +1 -1
  4. data/README.md +1 -1
  5. data/Rakefile +1 -1
  6. data/assets/textures/default.png +0 -0
  7. data/cyberarm_engine.gemspec +12 -9
  8. data/lib/cyberarm_engine.rb +20 -5
  9. data/lib/cyberarm_engine/animator.rb +6 -4
  10. data/lib/cyberarm_engine/background.rb +19 -15
  11. data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
  12. data/lib/cyberarm_engine/bounding_box.rb +18 -18
  13. data/lib/cyberarm_engine/cache.rb +4 -0
  14. data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
  15. data/lib/cyberarm_engine/common.rb +16 -16
  16. data/lib/cyberarm_engine/config_file.rb +2 -2
  17. data/lib/cyberarm_engine/game_object.rb +63 -72
  18. data/lib/cyberarm_engine/game_state.rb +6 -3
  19. data/lib/cyberarm_engine/model.rb +207 -0
  20. data/lib/cyberarm_engine/model/material.rb +21 -0
  21. data/lib/cyberarm_engine/model/model_object.rb +131 -0
  22. data/lib/cyberarm_engine/model/parser.rb +74 -0
  23. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
  24. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
  25. data/lib/cyberarm_engine/model_cache.rb +31 -0
  26. data/lib/cyberarm_engine/opengl.rb +28 -0
  27. data/lib/cyberarm_engine/opengl/light.rb +50 -0
  28. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
  29. data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
  30. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
  31. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
  32. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
  33. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
  34. data/lib/cyberarm_engine/{shader.rb → opengl/shader.rb} +51 -43
  35. data/lib/cyberarm_engine/opengl/texture.rb +69 -0
  36. data/lib/cyberarm_engine/ray.rb +5 -5
  37. data/lib/cyberarm_engine/stats.rb +21 -0
  38. data/lib/cyberarm_engine/text.rb +45 -31
  39. data/lib/cyberarm_engine/timer.rb +1 -1
  40. data/lib/cyberarm_engine/transform.rb +43 -20
  41. data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
  42. data/lib/cyberarm_engine/ui/dsl.rb +49 -10
  43. data/lib/cyberarm_engine/ui/element.rb +73 -21
  44. data/lib/cyberarm_engine/ui/elements/button.rb +121 -28
  45. data/lib/cyberarm_engine/ui/elements/check_box.rb +25 -33
  46. data/lib/cyberarm_engine/ui/elements/container.rb +113 -33
  47. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -0
  48. data/lib/cyberarm_engine/ui/elements/edit_line.rb +145 -45
  49. data/lib/cyberarm_engine/ui/elements/flow.rb +1 -3
  50. data/lib/cyberarm_engine/ui/elements/image.rb +32 -12
  51. data/lib/cyberarm_engine/ui/elements/label.rb +122 -16
  52. data/lib/cyberarm_engine/ui/elements/list_box.rb +82 -0
  53. data/lib/cyberarm_engine/ui/elements/progress.rb +6 -5
  54. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -0
  55. data/lib/cyberarm_engine/ui/elements/slider.rb +104 -0
  56. data/lib/cyberarm_engine/ui/elements/stack.rb +1 -3
  57. data/lib/cyberarm_engine/ui/elements/text_block.rb +156 -0
  58. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +40 -31
  59. data/lib/cyberarm_engine/ui/event.rb +7 -7
  60. data/lib/cyberarm_engine/ui/gui_state.rb +118 -6
  61. data/lib/cyberarm_engine/ui/style.rb +10 -9
  62. data/lib/cyberarm_engine/ui/theme.rb +84 -22
  63. data/lib/cyberarm_engine/vector.rb +33 -30
  64. data/lib/cyberarm_engine/version.rb +2 -2
  65. data/lib/cyberarm_engine/{engine.rb → window.rb} +32 -19
  66. metadata +87 -18
  67. data/lib/cyberarm_engine/gosu_ext/circle.rb +0 -9
@@ -0,0 +1,82 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ class ListBox < Button
4
+ attr_accessor :items
5
+ attr_reader :choose
6
+
7
+ def initialize(options = {}, block = nil)
8
+ @items = options[:items] || []
9
+ @choose = options[:choose] || @items.first
10
+
11
+ super(@choose, options, block)
12
+
13
+ @style.background_canvas.background = default(:background)
14
+
15
+ # TODO: "Clean Up" into own class?
16
+ @menu = Stack.new(parent: parent, width: @options[:width], theme: @options[:theme])
17
+ @menu.define_singleton_method(:recalculate_menu) do
18
+ @x = @__list_box.x
19
+ @y = @__list_box.y + @__list_box.height
20
+ end
21
+ @menu.instance_variable_set(:"@__list_box", self)
22
+
23
+ def @menu.recalculate
24
+ super
25
+
26
+ recalculate_menu
27
+ end
28
+
29
+ self.choose = @choose
30
+ end
31
+
32
+ def choose=(item)
33
+ valid = @items.detect { |i| i == item }
34
+ raise "Invalid value '#{item}' for choose, valid options were: #{@items.map { |i| "#{i.inspect}" }.join(", ")}" unless valid
35
+
36
+ @choose = item
37
+
38
+ self.value = item.to_s
39
+
40
+ recalculate
41
+ end
42
+
43
+ def released_left_mouse_button(_sender, _x, _y)
44
+ show_menu
45
+
46
+ :handled
47
+ end
48
+
49
+ def show_menu
50
+ @menu.clear
51
+
52
+ @items.each do |item|
53
+ btn = Button.new(
54
+ item,
55
+ {
56
+ parent: @menu,
57
+ width: 1.0,
58
+ theme: @options[:theme],
59
+ margin: 0,
60
+ border_color: 0x00ffffff
61
+ },
62
+ proc do
63
+ self.choose = item
64
+ @block&.call(item)
65
+ end
66
+ )
67
+
68
+ @menu.add(btn)
69
+ end
70
+ recalculate
71
+
72
+ root.gui_state.show_menu(@menu)
73
+ end
74
+
75
+ def recalculate
76
+ super
77
+
78
+ @menu.recalculate
79
+ end
80
+ end
81
+ end
82
+ end
@@ -5,7 +5,7 @@ module CyberarmEngine
5
5
  super(options, block)
6
6
 
7
7
  @fraction_background = Background.new(background: @style.fraction_background)
8
- self.value = options[:fraction] ? options[:fraction] : 0.0
8
+ self.value = options[:fraction] || 0.0
9
9
  end
10
10
 
11
11
  def render
@@ -14,9 +14,9 @@ module CyberarmEngine
14
14
 
15
15
  def recalculate
16
16
  _width = dimensional_size(@style.width, :width)
17
- _height= dimensional_size(@style.height,:height)
17
+ _height = dimensional_size(@style.height, :height)
18
18
  @width = _width
19
- @height= _height
19
+ @height = _height
20
20
 
21
21
  update_background
22
22
  end
@@ -43,8 +43,9 @@ module CyberarmEngine
43
43
  @fraction = decimal.clamp(0.0, 1.0)
44
44
  update_background
45
45
 
46
- return @fraction
46
+ publish(:changed, @fraction)
47
+ @fraction
47
48
  end
48
49
  end
49
50
  end
50
- end
51
+ end
@@ -0,0 +1,6 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ class Radio < Element
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,104 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ class Slider < Container
4
+ class Handle < Button
5
+ def initialize(*args)
6
+ super(*args)
7
+
8
+ event(:begin_drag)
9
+ event(:drag_update)
10
+ event(:end_drag)
11
+
12
+ subscribe :begin_drag do |_sender, x, y, _button|
13
+ @drag_start_pos = Vector.new(x, y)
14
+
15
+ :handled
16
+ end
17
+
18
+ subscribe :drag_update do |_sender, x, y, _button|
19
+ @parent.handle_dragged_to(x, y)
20
+
21
+ :handled
22
+ end
23
+
24
+ subscribe :end_drag do
25
+ @drag_start_pos = nil
26
+
27
+ :handled
28
+ end
29
+ end
30
+
31
+ def draggable?(button)
32
+ button == :left
33
+ end
34
+ end
35
+
36
+ attr_reader :range, :step_size, :value
37
+
38
+ def initialize(options = {}, block = nil)
39
+ super(options, block)
40
+
41
+ @range = @options[:range] || (0.0..1.0)
42
+ @step_size = @options[:step] || 0.1
43
+ @value = @options[:value] || (@range.first + @range.last) / 2
44
+
45
+ @handle = Handle.new("", parent: self, width: 8, height: 1.0) { close }
46
+ add(@handle)
47
+ end
48
+
49
+ def recalculate
50
+ _width = dimensional_size(@style.width, :width)
51
+ _height = dimensional_size(@style.height, :height)
52
+
53
+ @width = _width
54
+ @height = _height
55
+
56
+ position_handle
57
+ @handle.recalculate
58
+ @handle.update_background
59
+
60
+ update_background
61
+ end
62
+
63
+ def position_handle
64
+ @handle.x = @x + @style.padding_left + @style.border_thickness_left +
65
+ ((content_width - @handle.outer_width) * (@value - @range.min) / (@range.max - @range.min).to_f)
66
+
67
+ @handle.y = @y + @style.border_thickness_top + @style.padding_top
68
+ end
69
+
70
+ def draw
71
+ super
72
+
73
+ @handle.draw
74
+ end
75
+
76
+ def update
77
+ super
78
+
79
+ @tip = value.to_s
80
+ @handle.tip = @tip
81
+ end
82
+
83
+ def holding_left_mouse_button(_sender, x, y)
84
+ handle_dragged_to(x, y)
85
+
86
+ :handled
87
+ end
88
+
89
+ def handle_dragged_to(x, _y)
90
+ @ratio = ((x - @handle.width / 2) - @x) / (content_width - @handle.outer_width)
91
+
92
+ self.value = @ratio.clamp(0.0, 1.0) * (@range.max - @range.min) + @range.min
93
+ end
94
+
95
+ def value=(n)
96
+ @value = n
97
+ position_handle
98
+ @handle.recalculate
99
+
100
+ publish(:changed, @value)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -1,8 +1,6 @@
1
1
  module CyberarmEngine
2
2
  class Element
3
3
  class Stack < Container
4
- include Common
5
-
6
4
  def layout
7
5
  @children.each do |child|
8
6
  move_to_next_line(child)
@@ -10,4 +8,4 @@ module CyberarmEngine
10
8
  end
11
9
  end
12
10
  end
13
- end
11
+ end
@@ -0,0 +1,156 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ class TextBlock < Element
4
+ def initialize(text, options = {}, block = nil)
5
+ super(options, block)
6
+
7
+ @text = Text.new(
8
+ text, font: @options[:font], z: @z, color: @options[:color],
9
+ size: @options[:text_size], shadow: @options[:text_shadow],
10
+ shadow_size: @options[:text_shadow_size],
11
+ shadow_color: @options[:text_shadow_color]
12
+ )
13
+
14
+ @raw_text = text
15
+ end
16
+
17
+ def render
18
+ @text.draw
19
+ end
20
+
21
+ def clicked_left_mouse_button(_sender, _x, _y)
22
+ @block&.call(self) if @enabled
23
+
24
+ # return :handled
25
+ end
26
+
27
+ def recalculate
28
+ @width = 0
29
+ @height = 0
30
+
31
+ _width = dimensional_size(@style.width, :width)
32
+ _height = dimensional_size(@style.height, :height)
33
+
34
+ handle_text_wrapping(_width)
35
+
36
+ @width = _width || @text.width.round
37
+ @height = _height || @text.height.round
38
+
39
+ @text.y = @style.border_thickness_top + @style.padding_top + @y
40
+ @text.z = @z + 3
41
+
42
+ if (text_alignment = @options[:text_align])
43
+ case text_alignment
44
+ when :left
45
+ @text.x = @style.border_thickness_left + @style.padding_left + @x
46
+ when :center
47
+ @text.x = if @text.width <= outer_width
48
+ @x + outer_width / 2 - @text.width / 2
49
+ else # Act as left aligned
50
+ @style.border_thickness_left + @style.padding_left + @x
51
+ end
52
+ when :right
53
+ @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
54
+ end
55
+ end
56
+
57
+ update_background
58
+ end
59
+
60
+ def handle_text_wrapping(max_width)
61
+ max_width ||= @parent&.width
62
+ max_width ||= @x - (window.width + noncontent_width)
63
+ wrap_behavior = style.text_wrap
64
+ copy = @raw_text.to_s.dup
65
+
66
+ if line_width(copy[0]) <= max_width && line_width(copy) > max_width && wrap_behavior != :none
67
+ breaks = []
68
+ line_start = 0
69
+ line_end = copy.length
70
+
71
+ while line_start != copy.length
72
+ if line_width(copy[line_start...line_end]) > max_width
73
+ line_end = ((line_end - line_start) / 2.0)
74
+ line_end = 1.0 if line_end <= 1
75
+ elsif line_end < copy.length && line_width(copy[line_start...line_end + 1]) < max_width
76
+ # To small, grow!
77
+ # TODO: find a more efficient way
78
+ line_end += 1
79
+
80
+ else # FOUND IT!
81
+ entering_line_end = line_end.floor
82
+ max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63
83
+ reach = 0
84
+
85
+ if wrap_behavior == :word_wrap
86
+ max_reach.times do |i|
87
+ reach = i
88
+ break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /)
89
+ end
90
+
91
+ # puts "Max width: #{max_width}/#{line_width(@raw_text)} Reach: {#{reach}/#{max_reach}} Line Start: #{line_start}/#{line_end.floor} (#{copy.length}|#{@raw_text.length}) [#{entering_line_end}] '#{copy}' {#{copy[line_start...line_end]}}"
92
+ line_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation
93
+ end
94
+
95
+ breaks << line_end.floor
96
+ line_start = line_end.floor
97
+ line_end = copy.length
98
+
99
+ break if entering_line_end == copy.length || reach == max_reach
100
+ end
101
+ end
102
+
103
+ breaks.each_with_index do |pos, index|
104
+ copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
105
+ end
106
+ end
107
+
108
+ @text.text = copy
109
+ end
110
+
111
+ def line_width(text)
112
+ (@text.textobject.markup_width(text) + noncontent_width)
113
+ end
114
+
115
+ def value
116
+ @raw_text
117
+ end
118
+
119
+ def value=(value)
120
+ @raw_text = value.to_s.chomp
121
+
122
+ old_width = width
123
+ old_height = height
124
+ recalculate
125
+
126
+ root.gui_state.request_recalculate if old_width != width || old_height != height
127
+
128
+ publish(:changed, self.value)
129
+ end
130
+ end
131
+
132
+ class Banner < TextBlock
133
+ end
134
+
135
+ class Title < TextBlock
136
+ end
137
+
138
+ class Subtitle < TextBlock
139
+ end
140
+
141
+ class Tagline < TextBlock
142
+ end
143
+
144
+ class Caption < TextBlock
145
+ end
146
+
147
+ class Para < TextBlock
148
+ end
149
+
150
+ class Inscription < TextBlock
151
+ end
152
+
153
+ class ToolTip < TextBlock
154
+ end
155
+ end
156
+ end
@@ -1,56 +1,65 @@
1
1
  module CyberarmEngine
2
2
  class Element
3
3
  class ToggleButton < Button
4
- attr_reader :toggled
4
+ attr_reader :toggled, :value
5
5
 
6
6
  def initialize(options, block = nil)
7
- super(options[:checkmark], options, block)
8
- @toggled = options[:toggled] || false
9
- if @toggled
10
- @text.text = @options[:checkmark]
7
+ if options.dig(:theme, :ToggleButton, :checkmark_image)
8
+ options[:theme][:ToggleButton][:image_width] ||= options[:theme][:Label][:text_size]
9
+ super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block)
10
+
11
+ @_image = @image
11
12
  else
12
- @text.text = ""
13
+ super(options[:checkmark], options, block)
13
14
  end
14
15
 
15
- return self
16
- end
16
+ @value = options[:checked] || false
17
17
 
18
- def toggled=(boolean)
19
- @toggled = !boolean
20
- toggle
18
+ if @value
19
+ @image = @_image if @_image
20
+ @raw_text = @options[:checkmark]
21
+ else
22
+ @image = nil
23
+ @raw_text = ""
24
+ end
21
25
  end
22
26
 
23
- def clicked_left_mouse_button(sender, x, y)
24
- toggle
27
+ def clicked_left_mouse_button(_sender, _x, _y)
28
+ self.value = !@value
25
29
 
26
30
  @block.call(self) if @block
27
31
 
28
- return :handled
29
- end
30
-
31
- def toggle
32
- if @toggled
33
- @toggled = false
34
- @text.text = ""
35
- else
36
- @toggled = true
37
- @text.text = @options[:checkmark]
38
- end
32
+ :handled
39
33
  end
40
34
 
41
35
  def recalculate
42
36
  super
37
+ return if @image
38
+
39
+ _width = dimensional_size(@style.width, :width)
40
+ _height = dimensional_size(@style.height, :height)
41
+
42
+ @width = _width || @text.textobject.text_width(@options[:checkmark])
43
+ @height = _height || @text.height
43
44
 
44
- _width = dimensional_size(@style.width, :width)
45
- _height= dimensional_size(@style.height,:height)
46
- @width = _width ? _width : @text.textobject.text_width(@options[:checkmark])
47
- @height = _height ? _height : @text.height
48
45
  update_background
49
46
  end
50
47
 
51
- def value
52
- @toggled
48
+ def value=(boolean)
49
+ @value = boolean
50
+
51
+ if boolean
52
+ @image = @_image if @_image
53
+ @raw_text = @options[:checkmark]
54
+ else
55
+ @image = nil
56
+ @raw_text = ""
57
+ end
58
+
59
+ recalculate
60
+
61
+ publish(:changed, @value)
53
62
  end
54
63
  end
55
64
  end
56
- end
65
+ end