cyberarm_engine 0.13.1 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
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