cyberarm_engine 0.14.0 → 0.18.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile +1 -1
  4. data/README.md +5 -4
  5. data/Rakefile +1 -1
  6. data/assets/textures/default.png +0 -0
  7. data/assets/textures/logo.png +0 -0
  8. data/cyberarm_engine.gemspec +11 -9
  9. data/lib/cyberarm_engine.rb +19 -7
  10. data/lib/cyberarm_engine/animator.rb +13 -11
  11. data/lib/cyberarm_engine/background.rb +19 -15
  12. data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
  13. data/lib/cyberarm_engine/bounding_box.rb +18 -18
  14. data/lib/cyberarm_engine/builtin/intro_state.rb +128 -0
  15. data/lib/cyberarm_engine/cache.rb +4 -0
  16. data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
  17. data/lib/cyberarm_engine/common.rb +18 -13
  18. data/lib/cyberarm_engine/config_file.rb +2 -2
  19. data/lib/cyberarm_engine/game_object.rb +63 -72
  20. data/lib/cyberarm_engine/game_state.rb +11 -3
  21. data/lib/cyberarm_engine/model.rb +207 -0
  22. data/lib/cyberarm_engine/model/material.rb +21 -0
  23. data/lib/cyberarm_engine/model/model_object.rb +131 -0
  24. data/lib/cyberarm_engine/model/parser.rb +74 -0
  25. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
  26. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
  27. data/lib/cyberarm_engine/model_cache.rb +31 -0
  28. data/lib/cyberarm_engine/opengl.rb +28 -0
  29. data/lib/cyberarm_engine/opengl/light.rb +50 -0
  30. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
  31. data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
  32. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
  33. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
  34. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
  35. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
  36. data/lib/cyberarm_engine/{shader.rb → opengl/shader.rb} +51 -43
  37. data/lib/cyberarm_engine/opengl/texture.rb +69 -0
  38. data/lib/cyberarm_engine/ray.rb +5 -5
  39. data/lib/cyberarm_engine/stats.rb +2 -2
  40. data/lib/cyberarm_engine/text.rb +51 -27
  41. data/lib/cyberarm_engine/timer.rb +1 -1
  42. data/lib/cyberarm_engine/transform.rb +43 -20
  43. data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
  44. data/lib/cyberarm_engine/ui/dsl.rb +45 -12
  45. data/lib/cyberarm_engine/ui/element.rb +211 -61
  46. data/lib/cyberarm_engine/ui/elements/button.rb +72 -42
  47. data/lib/cyberarm_engine/ui/elements/check_box.rb +5 -2
  48. data/lib/cyberarm_engine/ui/elements/container.rb +81 -29
  49. data/lib/cyberarm_engine/ui/elements/edit_box.rb +175 -2
  50. data/lib/cyberarm_engine/ui/elements/edit_line.rb +139 -48
  51. data/lib/cyberarm_engine/ui/elements/flow.rb +1 -1
  52. data/lib/cyberarm_engine/ui/elements/image.rb +32 -12
  53. data/lib/cyberarm_engine/ui/elements/list_box.rb +78 -2
  54. data/lib/cyberarm_engine/ui/elements/progress.rb +5 -5
  55. data/lib/cyberarm_engine/ui/elements/radio.rb +1 -1
  56. data/lib/cyberarm_engine/ui/elements/slider.rb +13 -16
  57. data/lib/cyberarm_engine/ui/elements/stack.rb +1 -1
  58. data/lib/cyberarm_engine/ui/elements/text_block.rb +153 -0
  59. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +27 -19
  60. data/lib/cyberarm_engine/ui/event.rb +7 -7
  61. data/lib/cyberarm_engine/ui/gui_state.rb +88 -16
  62. data/lib/cyberarm_engine/ui/style.rb +23 -11
  63. data/lib/cyberarm_engine/ui/theme.rb +95 -21
  64. data/lib/cyberarm_engine/vector.rb +33 -30
  65. data/lib/cyberarm_engine/version.rb +2 -2
  66. data/lib/cyberarm_engine/window.rb +35 -18
  67. metadata +70 -18
  68. data/lib/cyberarm_engine/ui/elements/label.rb +0 -52
@@ -1,67 +1,97 @@
1
1
  module CyberarmEngine
2
2
  class Element
3
- class Button < Label
4
- def initialize(text, options = {}, block = nil)
5
- super(text, options, block)
3
+ class Button < TextBlock
4
+ def initialize(text_or_image, options = {}, block = nil)
5
+ @image = nil
6
+ @scale_x = 1
7
+ @scale_y = 1
6
8
 
7
- @style.background_canvas.background = default(:background)
8
- end
9
+ @image = text_or_image if text_or_image.is_a?(Gosu::Image)
9
10
 
10
- def render
11
- draw_text
12
- end
11
+ super(text_or_image, options, block)
13
12
 
14
- def draw_text
15
- @text.draw
13
+ @style.background_canvas.background = @style.background
16
14
  end
17
15
 
18
- def enter(sender)
19
- @focus = false unless window.button_down?(Gosu::MsLeft)
20
-
21
- if @focus
22
- @style.background_canvas.background = default(:active, :background)
23
- @text.color = default(:active, :color)
16
+ def render
17
+ if @image
18
+ draw_image
24
19
  else
25
- @style.background_canvas.background = default(:hover, :background)
26
- @text.color = default(:hover, :color)
20
+ draw_text
27
21
  end
28
-
29
- return :handled
30
22
  end
31
23
 
32
- def left_mouse_button(sender, x, y)
33
- @focus = true
34
- @style.background_canvas.background = default(:active, :background)
35
- window.current_state.focus = self
36
- @text.color = default(:active, :color)
24
+ def draw_image
25
+ @image.draw(
26
+ @style.border_thickness_left + @style.padding_left + @x,
27
+ @style.border_thickness_top + @style.padding_top + @y,
28
+ @z + 2,
29
+ @scale_x, @scale_y, @text.color
30
+ )
31
+ end
37
32
 
38
- return :handled
33
+ def draw_text
34
+ @text.draw
39
35
  end
40
36
 
41
- def released_left_mouse_button(sender,x, y)
42
- enter(sender)
37
+ def recalculate
38
+ unless @enabled
39
+ @style.background_canvas.background = @style.disabled[:background]
40
+ @text.color = @style.disabled[:color]
41
+ else
42
+ @style.background_canvas.background = @style.background
43
+ @text.color = @style.color
44
+ end
43
45
 
44
- return :handled
46
+ if @image
47
+ @width = 0
48
+ @height = 0
49
+
50
+ _width = dimensional_size(@style.image_width, :width)
51
+ _height = dimensional_size(@style.image_height, :height)
52
+
53
+ if _width && _height
54
+ @scale_x = _width.to_f / @image.width
55
+ @scale_y = _height.to_f / @image.height
56
+ elsif _width
57
+ @scale_x = _width.to_f / @image.width
58
+ @scale_y = @scale_x
59
+ elsif _height
60
+ @scale_y = _height.to_f / @image.height
61
+ @scale_x = @scale_y
62
+ else
63
+ @scale_x = 1
64
+ @scale_y = 1
65
+ end
66
+
67
+ @width = _width || @image.width.round * @scale_x
68
+ @height = _height || @image.height.round * @scale_y
69
+
70
+ update_background
71
+ else
72
+ super
73
+ end
45
74
  end
46
75
 
47
- def clicked_left_mouse_button(sender, x, y)
48
- @block.call(self) if @block
49
-
50
- return :handled
76
+ def value
77
+ @image || super
51
78
  end
52
79
 
53
- def leave(sender)
54
- @style.background_canvas.background = default(:background)
55
- @text.color = default(:color)
80
+ def value=(value)
81
+ if value.is_a?(Gosu::Image)
82
+ @image = value
83
+ else
84
+ super
85
+ end
56
86
 
57
- return :handled
58
- end
87
+ old_width = width
88
+ old_height = height
89
+ recalculate
59
90
 
60
- def blur(sender)
61
- @focus = false
91
+ root.gui_state.request_recalculate if old_width != width || old_height != height
62
92
 
63
- return :handled
93
+ publish(:changed, self.value)
64
94
  end
65
95
  end
66
96
  end
67
- end
97
+ end
@@ -5,8 +5,11 @@ module CyberarmEngine
5
5
  super(options, block)
6
6
  options[:toggled] = options[:checked]
7
7
 
8
+ options[:parent] = self
8
9
  @toggle_button = ToggleButton.new(options)
9
- @label = Label.new(text, options)
10
+
11
+ options[:parent] = self
12
+ @label = TextBlock.new(text, options)
10
13
 
11
14
  @label.subscribe(:holding_left_mouse_button) do |sender, x, y|
12
15
  @toggle_button.left_mouse_button(sender, x, y)
@@ -48,4 +51,4 @@ module CyberarmEngine
48
51
  end
49
52
  end
50
53
  end
51
- end
54
+ end
@@ -4,19 +4,20 @@ 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
@@ -44,12 +45,31 @@ module CyberarmEngine
44
45
  root.gui_state.request_recalculate
45
46
  end
46
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
+
56
+ root.gui_state.request_recalculate
57
+ end
58
+
47
59
  def render
48
60
  Gosu.clip_to(@x, @y, width, height) do
49
61
  @children.each(&:draw)
50
62
  end
51
63
  end
52
64
 
65
+ def debug_draw
66
+ super
67
+
68
+ @children.each do |child|
69
+ child.debug_draw
70
+ end
71
+ end
72
+
53
73
  def update
54
74
  @children.each(&:update)
55
75
  end
@@ -73,6 +93,8 @@ module CyberarmEngine
73
93
 
74
94
  def recalculate
75
95
  @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
96
+ @current_position += @scroll_position
97
+
76
98
  return unless visible?
77
99
 
78
100
  Stats.increment(:gui_recalculations_last_frame, 1)
@@ -85,13 +107,14 @@ module CyberarmEngine
85
107
  @width = @style.width = window.width
86
108
  @height = @style.height = window.height
87
109
  else
88
- @width, @height = 0, 0
110
+ @width = 0
111
+ @height = 0
89
112
 
90
113
  _width = dimensional_size(@style.width, :width)
91
- _height= dimensional_size(@style.height,:height)
114
+ _height = dimensional_size(@style.height, :height)
92
115
 
93
- @width = _width ? _width : (@children.map {|c| c.x + c.outer_width }.max || 0).round
94
- @height = _height ? _height : (@children.map {|c| c.y + c.outer_height}.max || 0).round
116
+ @width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).round
117
+ @height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).round
95
118
  end
96
119
 
97
120
  # Move child to parent after positioning
@@ -115,33 +138,35 @@ module CyberarmEngine
115
138
 
116
139
  def max_width
117
140
  _width = dimensional_size(@style.width, :width)
118
- _width ? outer_width : window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
141
+ if _width
142
+ outer_width
143
+ else
144
+ window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
145
+ end
119
146
  end
120
147
 
121
148
  def fits_on_line?(element) # Flow
122
149
  p [@options[:id], @width] if @options[:id]
123
150
  @current_position.x + element.outer_width <= max_width &&
124
- @current_position.x + element.outer_width <= window.width
151
+ @current_position.x + element.outer_width <= window.width
125
152
  end
126
153
 
127
154
  def position_on_current_line(element) # Flow
128
155
  element.x = element.style.margin_left + @current_position.x
129
156
  element.y = element.style.margin_top + @current_position.y
130
157
 
131
- element.recalculate
132
-
133
158
  @current_position.x += element.outer_width
134
159
  @current_position.x = @style.margin_left if @current_position.x >= max_width
135
160
  end
136
161
 
137
- def tallest_neighbor(querier, y_position) # Flow
162
+ def tallest_neighbor(querier, _y_position) # Flow
138
163
  response = querier
139
164
  @children.each do |child|
140
165
  response = child if child.outer_height > response.outer_height
141
166
  break if child == querier
142
167
  end
143
168
 
144
- return response
169
+ response
145
170
  end
146
171
 
147
172
  def position_on_next_line(child) # Flow
@@ -151,8 +176,6 @@ module CyberarmEngine
151
176
  child.x = child.style.margin_left + @current_position.x
152
177
  child.y = child.style.margin_top + @current_position.y
153
178
 
154
- child.recalculate
155
-
156
179
  @current_position.x += child.outer_width
157
180
  end
158
181
 
@@ -160,33 +183,62 @@ module CyberarmEngine
160
183
  element.x = element.style.margin_left + @current_position.x
161
184
  element.y = element.style.margin_top + @current_position.y
162
185
 
163
- element.recalculate
164
-
165
186
  @current_position.y += element.outer_height
166
187
  end
167
188
 
168
- # def mouse_wheel_up(sender, x, y)
169
- # @children.each {|c| c.y -= @scroll_speed}
170
- # @children.each {|c| c.recalculate}
171
- # end
189
+ def mouse_wheel_up(sender, x, y)
190
+ return unless @style.scroll
191
+
192
+ if @scroll_position.y < 0
193
+ @scroll_position.y += @scroll_speed
194
+ @scroll_position.y = 0 if @scroll_position.y > 0
195
+ recalculate
196
+
197
+ return :handled
198
+ end
199
+ end
200
+
201
+ def mouse_wheel_down(sender, x, y)
202
+ return unless @style.scroll
203
+
204
+ return unless height < scroll_height
205
+
206
+ if @scroll_position.y.abs < max_scroll_height
207
+ @scroll_position.y -= @scroll_speed
208
+ @scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
209
+ recalculate
172
210
 
173
- # def mouse_wheel_down(sender, x, y)
174
- # @children.each {|c| c.y += @scroll_speed}
175
- # @children.each {|c| c.recalculate}
176
- # end
211
+ return :handled
212
+ end
213
+ end
214
+
215
+ def scroll_top
216
+ @scroll_position.y
217
+ end
218
+
219
+ def scroll_top=(n)
220
+ n = 0 if n <= 0
221
+ @scroll_position.y = -n
222
+
223
+ if max_scroll_height.positive?
224
+ @scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
225
+ else
226
+ @scroll_position.y = 0
227
+ end
228
+ end
177
229
 
178
230
  def value
179
- @children.map {|c| c.class}.join(", ")
231
+ @children.map { |c| c.class }.join(", ")
180
232
  end
181
233
 
182
234
  def to_s
183
235
  "#{self.class} x=#{x} y=#{y} width=#{width} height=#{height} children=#{@children.size}"
184
236
  end
185
237
 
186
- def write_tree(indent = "", index = 0)
238
+ def write_tree(indent = "", _index = 0)
187
239
  puts self
188
240
 
189
- indent = indent + " "
241
+ indent += " "
190
242
  @children.each_with_index do |child, i|
191
243
  print "#{indent}#{i}: "
192
244
 
@@ -1,6 +1,179 @@
1
1
  module CyberarmEngine
2
2
  class Element
3
- class EditBox < 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
4
177
  end
5
178
  end
6
- end
179
+ end