cyberarm_engine 0.14.0 → 0.18.0

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