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
@@ -2,13 +2,32 @@ module CyberarmEngine
2
2
  class Element
3
3
  class CheckBox < Flow
4
4
  def initialize(text, options, block = nil)
5
- super({}, block = nil)
5
+ super(options, block)
6
6
  options[:toggled] = options[:checked]
7
7
 
8
8
  @toggle_button = ToggleButton.new(options)
9
- @label = Label.new(text, options)
9
+ @label = TextBlock.new(text, options)
10
10
 
11
- define_label_singletons
11
+ @label.subscribe(:holding_left_mouse_button) do |sender, x, y|
12
+ @toggle_button.left_mouse_button(sender, x, y)
13
+ end
14
+
15
+ @label.subscribe(:released_left_mouse_button) do |sender, x, y|
16
+ @toggle_button.released_left_mouse_button(sender, x, y)
17
+ end
18
+
19
+ @label.subscribe(:clicked_left_mouse_button) do |sender, x, y|
20
+ @toggle_button.clicked_left_mouse_button(sender, x, y)
21
+ publish(:changed, @toggle_button.value)
22
+ end
23
+
24
+ @label.subscribe(:enter) do |sender|
25
+ @toggle_button.enter(sender)
26
+ end
27
+
28
+ @label.subscribe(:leave) do |sender|
29
+ @toggle_button.leave(sender)
30
+ end
12
31
 
13
32
  add(@toggle_button)
14
33
  add(@label)
@@ -24,36 +43,9 @@ module CyberarmEngine
24
43
  end
25
44
 
26
45
  def value=(bool)
27
- @toggle_button.vlaue = bool
28
- end
29
-
30
- def define_label_singletons
31
- @label.define_singleton_method(:_toggle_button) do |button|
32
- @_toggle_button = button
33
- end
34
-
35
- @label._toggle_button(@toggle_button)
36
-
37
- @label.define_singleton_method(:holding_left_mouse_button) do |sender, x, y|
38
- @_toggle_button.left_mouse_button(sender, x, y)
39
- end
40
-
41
- @label.define_singleton_method(:released_left_mouse_button) do |sender, x, y|
42
- @_toggle_button.released_left_mouse_button(sender, x, y)
43
- end
44
-
45
- @label.define_singleton_method(:clicked_left_mouse_button) do |sender, x, y|
46
- @_toggle_button.clicked_left_mouse_button(sender, x, y)
47
- end
48
-
49
- @label.define_singleton_method(:enter) do |sender|
50
- @_toggle_button.enter(sender)
51
- end
52
-
53
- @label.define_singleton_method(:leave) do |sender|
54
- @_toggle_button.leave(sender)
55
- end
46
+ @toggle_button.value = bool
47
+ publish(:changed, @toggle_button.value)
56
48
  end
57
49
  end
58
50
  end
59
- end
51
+ end
@@ -4,31 +4,32 @@ module CyberarmEngine
4
4
  include Common
5
5
 
6
6
  attr_accessor :stroke_color, :fill_color
7
- attr_reader :children, :gui_state
8
- attr_reader :scroll_x, :scroll_y
7
+ attr_reader :children, :gui_state, :scroll_position
9
8
 
10
9
  def initialize(options = {}, block = nil)
11
10
  @gui_state = options.delete(:gui_state)
12
11
  super
13
12
 
14
- @scroll_x, @scroll_y = 0, 0
15
- @scroll_speed = 10
13
+ @scroll_position = Vector.new(0, 0)
14
+ @scroll_speed = 40
16
15
 
17
16
  @text_color = options[:color]
18
17
 
19
18
  @children = []
19
+
20
+ event(:window_size_changed)
20
21
  end
21
22
 
22
23
  def build
23
24
  @block.call(self) if @block
24
25
 
25
- recalculate
26
+ root.gui_state.request_recalculate
26
27
  end
27
28
 
28
29
  def add(element)
29
30
  @children << element
30
31
 
31
- recalculate
32
+ root.gui_state.request_recalculate
32
33
  end
33
34
 
34
35
  def clear(&block)
@@ -41,7 +42,17 @@ module CyberarmEngine
41
42
 
42
43
  $__current_container__ = old_container
43
44
 
44
- recalculate
45
+ root.gui_state.request_recalculate
46
+ end
47
+
48
+ def apend(&block)
49
+ old_container = $__current_container__
50
+
51
+ $__current_container__ = self
52
+ block.call(self) if block
53
+
54
+ $__current_container__ = old_container
55
+
45
56
  root.gui_state.request_recalculate
46
57
  end
47
58
 
@@ -49,6 +60,31 @@ module CyberarmEngine
49
60
  Gosu.clip_to(@x, @y, width, height) do
50
61
  @children.each(&:draw)
51
62
  end
63
+
64
+ if false # DEBUG
65
+ Gosu.flush
66
+
67
+ Gosu.draw_line(
68
+ x, y, Gosu::Color::RED,
69
+ x + outer_width, y, Gosu::Color::RED,
70
+ Float::INFINITY
71
+ )
72
+ Gosu.draw_line(
73
+ x + outer_width, y, Gosu::Color::RED,
74
+ x + outer_width, y + outer_height, Gosu::Color::RED,
75
+ Float::INFINITY
76
+ )
77
+ Gosu.draw_line(
78
+ x + outer_width, y + outer_height, Gosu::Color::RED,
79
+ x, y + outer_height, Gosu::Color::RED,
80
+ Float::INFINITY
81
+ )
82
+ Gosu.draw_line(
83
+ x, outer_height, Gosu::Color::RED,
84
+ x, y, Gosu::Color::RED,
85
+ Float::INFINITY
86
+ )
87
+ end
52
88
  end
53
89
 
54
90
  def update
@@ -57,6 +93,8 @@ module CyberarmEngine
57
93
 
58
94
  def hit_element?(x, y)
59
95
  @children.reverse_each do |child|
96
+ next unless child.visible?
97
+
60
98
  case child
61
99
  when Container
62
100
  if element = child.hit_element?(x, y)
@@ -72,7 +110,12 @@ module CyberarmEngine
72
110
 
73
111
  def recalculate
74
112
  @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
113
+ @current_position += @scroll_position
114
+
75
115
  return unless visible?
116
+
117
+ Stats.increment(:gui_recalculations_last_frame, 1)
118
+
76
119
  stylize
77
120
 
78
121
  layout
@@ -81,24 +124,26 @@ module CyberarmEngine
81
124
  @width = @style.width = window.width
82
125
  @height = @style.height = window.height
83
126
  else
84
- @width, @height = 0, 0
127
+ @width = 0
128
+ @height = 0
85
129
 
86
130
  _width = dimensional_size(@style.width, :width)
87
- _height= dimensional_size(@style.height,:height)
131
+ _height = dimensional_size(@style.height, :height)
88
132
 
89
- @width = _width ? _width : (@children.map {|c| c.x + c.outer_width }.max || 0).round
90
- @height = _height ? _height : (@children.map {|c| c.y + c.outer_height}.max || 0).round
133
+ @width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).round
134
+ @height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).round
91
135
  end
92
136
 
93
-
94
137
  # Move child to parent after positioning
95
138
  @children.each do |child|
96
- child.x += @x
97
- child.y += @y
139
+ child.x += (@x + @style.border_thickness_left) - style.margin_left
140
+ child.y += (@y + @style.border_thickness_top) - style.margin_top
98
141
 
99
142
  child.stylize
100
143
  child.recalculate
101
144
  child.reposition # TODO: Implement top,bottom,left,center, and right positioning
145
+
146
+ Stats.increment(:gui_recalculations_last_frame, 1)
102
147
  end
103
148
 
104
149
  update_background
@@ -109,32 +154,36 @@ module CyberarmEngine
109
154
  end
110
155
 
111
156
  def max_width
112
- @max_width ? @max_width : window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
157
+ _width = dimensional_size(@style.width, :width)
158
+ if _width
159
+ outer_width
160
+ else
161
+ window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
162
+ end
113
163
  end
114
164
 
115
165
  def fits_on_line?(element) # Flow
166
+ p [@options[:id], @width] if @options[:id]
116
167
  @current_position.x + element.outer_width <= max_width &&
117
- @current_position.x + element.outer_width <= window.width
168
+ @current_position.x + element.outer_width <= window.width
118
169
  end
119
170
 
120
171
  def position_on_current_line(element) # Flow
121
172
  element.x = element.style.margin_left + @current_position.x
122
173
  element.y = element.style.margin_top + @current_position.y
123
174
 
124
- element.recalculate
125
-
126
175
  @current_position.x += element.outer_width
127
176
  @current_position.x = @style.margin_left if @current_position.x >= max_width
128
177
  end
129
178
 
130
- def tallest_neighbor(querier, y_position) # Flow
179
+ def tallest_neighbor(querier, _y_position) # Flow
131
180
  response = querier
132
181
  @children.each do |child|
133
182
  response = child if child.outer_height > response.outer_height
134
183
  break if child == querier
135
184
  end
136
185
 
137
- return response
186
+ response
138
187
  end
139
188
 
140
189
  def position_on_next_line(child) # Flow
@@ -144,8 +193,6 @@ module CyberarmEngine
144
193
  child.x = child.style.margin_left + @current_position.x
145
194
  child.y = child.style.margin_top + @current_position.y
146
195
 
147
- child.recalculate
148
-
149
196
  @current_position.x += child.outer_width
150
197
  end
151
198
 
@@ -153,23 +200,56 @@ module CyberarmEngine
153
200
  element.x = element.style.margin_left + @current_position.x
154
201
  element.y = element.style.margin_top + @current_position.y
155
202
 
156
- element.recalculate
157
-
158
203
  @current_position.y += element.outer_height
159
204
  end
160
205
 
161
- # def mouse_wheel_up(sender, x, y)
162
- # @children.each {|c| c.y -= @scroll_speed}
163
- # @children.each {|c| c.recalculate}
164
- # end
206
+ def mouse_wheel_up(sender, x, y)
207
+ return unless @style.scroll
208
+ return if height < max_scroll_height
165
209
 
166
- # def mouse_wheel_down(sender, x, y)
167
- # @children.each {|c| c.y += @scroll_speed}
168
- # @children.each {|c| c.recalculate}
169
- # end
210
+ if @scroll_position.y < 0
211
+ @scroll_position.y += @scroll_speed
212
+ @scroll_position.y = 0 if @scroll_position.y > 0
213
+ recalculate
214
+
215
+ return :handled
216
+ end
217
+ end
218
+
219
+ def mouse_wheel_down(sender, x, y)
220
+ return unless @style.scroll
221
+ return if height < max_scroll_height
222
+
223
+ if @scroll_position.y.abs < max_scroll_height
224
+ @scroll_position.y -= @scroll_speed
225
+ @scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
226
+ recalculate
227
+
228
+ return :handled
229
+ end
230
+ end
170
231
 
171
232
  def value
172
- @children.map {|c| c.class}.join(", ")
233
+ @children.map { |c| c.class }.join(", ")
234
+ end
235
+
236
+ def to_s
237
+ "#{self.class} x=#{x} y=#{y} width=#{width} height=#{height} children=#{@children.size}"
238
+ end
239
+
240
+ def write_tree(indent = "", _index = 0)
241
+ puts self
242
+
243
+ indent += " "
244
+ @children.each_with_index do |child, i|
245
+ print "#{indent}#{i}: "
246
+
247
+ if child.is_a?(Container)
248
+ child.write_tree(indent)
249
+ else
250
+ puts child
251
+ end
252
+ end
173
253
  end
174
254
  end
175
255
  end
@@ -0,0 +1,179 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ class EditBox < EditLine
4
+ def initialize(*args)
5
+ super(*args)
6
+
7
+ @active_line = 0
8
+
9
+ @repeatable_keys = [
10
+ {
11
+ key: Gosu::KB_UP,
12
+ down: false,
13
+ repeat_delay: 50,
14
+ last_repeat: 0,
15
+ action: proc { move(:up) }
16
+ },
17
+ {
18
+ key: Gosu::KB_DOWN,
19
+ down: false,
20
+ repeat_delay: 50,
21
+ last_repeat: 0,
22
+ action: proc { move(:down) }
23
+ }
24
+ ]
25
+ end
26
+
27
+ def update
28
+ super
29
+
30
+ caret_stay_left_of_last_newline
31
+ calculate_active_line
32
+
33
+ @repeatable_keys.each do |key|
34
+ if key[:down] && (Gosu.milliseconds > key[:last_repeat] + key[:repeat_delay])
35
+ key[:action].call
36
+ key[:last_repeat] = Gosu.milliseconds
37
+ end
38
+ end
39
+ end
40
+
41
+ def draw_caret
42
+ Gosu.draw_rect(caret_position, @text.y + @active_line * @text.textobject.height, @caret_width, @caret_height,
43
+ @caret_color, @z)
44
+ end
45
+
46
+ def draw_selection
47
+ selection_width = caret_position - selection_start_position
48
+
49
+ Gosu.draw_rect(selection_start_position, @text.y, selection_width, @text.textobject.height,
50
+ default(:selection_color), @z)
51
+ end
52
+
53
+ def text_input_position_for(_method)
54
+ line = @text_input.text[0...@text_input.caret_pos].lines.last
55
+ _x = @text.x + @offset_x
56
+
57
+ if @type == :password
58
+ _x + @text.width(default(:password_character) * line.length)
59
+ else
60
+ _x + @text.width(line)
61
+ end
62
+ end
63
+
64
+ def set_position(int)
65
+ int = 0 if int < 0
66
+ @text_input.selection_start = @text_input.caret_pos = int
67
+ end
68
+
69
+ def calculate_active_line
70
+ sub_text = @text_input.text[0...@text_input.caret_pos]
71
+ @active_line = sub_text.lines.size - 1
72
+ end
73
+
74
+ def caret_stay_left_of_last_newline
75
+ @text_input.text += "\n" unless @text_input.text.end_with?("\n")
76
+
77
+ eof = @text_input.text.chomp.length
78
+ set_position(eof) if @text_input.caret_pos > eof
79
+ end
80
+
81
+ def caret_position_under_mouse(mouse_x, mouse_y)
82
+ active_line = row_at(mouse_y)
83
+ right_offset = column_at(mouse_x, mouse_y)
84
+
85
+ buffer = @text_input.text.lines[0..active_line].join if active_line != 0
86
+ buffer = @text_input.text.lines.first if active_line == 0
87
+ line = buffer.lines.last
88
+
89
+ if buffer.chars.last == "\n"
90
+ (buffer.length - line.length) + right_offset - 1
91
+ else
92
+ (buffer.length - line.length) + right_offset
93
+ end
94
+ end
95
+
96
+ def move_caret_to_mouse(mouse_x, mouse_y)
97
+ set_position(caret_position_under_mouse(mouse_x, mouse_y))
98
+ end
99
+
100
+ def row_at(y)
101
+ ((y - @text.y) / @text.textobject.height).round
102
+ end
103
+
104
+ def column_at(x, y)
105
+ row = row_at(y)
106
+
107
+ buffer = @text_input.text.lines[0..row].join if row != 0
108
+ buffer = @text_input.text.lines.first if row == 0
109
+
110
+ line = @text_input.text.lines[row]
111
+ line ||= ""
112
+ column = 0
113
+
114
+ line.length.times do |_i|
115
+ break if @text.textobject.text_width(line[0...column]) >= (x - @text.x).clamp(0.0, Float::INFINITY)
116
+
117
+ column += 1
118
+ end
119
+
120
+ column
121
+ end
122
+
123
+ def button_down(id)
124
+ super
125
+
126
+ @repeatable_keys.detect do |key|
127
+ next unless key[:key] == id
128
+
129
+ key[:down] = true
130
+ key[:last_repeat] = Gosu.milliseconds + key[:repeat_delay]
131
+ return true
132
+ end
133
+
134
+ case id
135
+ when Gosu::KB_ENTER, Gosu::KB_RETURN
136
+ caret_pos = @text_input.caret_pos
137
+ @text_input.text = @text_input.text.insert(@text_input.caret_pos, "\n")
138
+ @text_input.caret_pos = @text_input.selection_start = caret_pos + 1
139
+ end
140
+ end
141
+
142
+ def button_up(id)
143
+ super
144
+
145
+ @repeatable_keys.detect do |key|
146
+ if key[:key] == id
147
+ key[:down] = false
148
+ return true
149
+ end
150
+ end
151
+ end
152
+
153
+ def move(direction)
154
+ pos = @text_input.caret_pos
155
+ line = nil
156
+
157
+ case direction
158
+ when :up
159
+ return if @active_line == 0
160
+ when :down
161
+ return if @active_line == @text_input.text.chomp.lines
162
+
163
+ text = @text_input.text.chomp.lines[0..@active_line].join("\n")
164
+ pos = text.length
165
+ end
166
+
167
+ set_position(pos)
168
+ end
169
+
170
+ def drag_update(_sender, x, y, _button)
171
+ int = caret_position_under_mouse(x, y)
172
+ int = 0 if int < 0
173
+ @text_input.caret_pos = int
174
+
175
+ :handled
176
+ end
177
+ end
178
+ end
179
+ end