cyberarm_engine 0.12.0 → 0.15.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/Gemfile +1 -1
- data/README.md +33 -3
- data/Rakefile +1 -1
- data/assets/textures/default.png +0 -0
- data/cyberarm_engine.gemspec +11 -8
- data/lib/cyberarm_engine.rb +24 -4
- data/lib/cyberarm_engine/animator.rb +56 -0
- data/lib/cyberarm_engine/background.rb +19 -15
- data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
- data/lib/cyberarm_engine/bounding_box.rb +18 -18
- data/lib/cyberarm_engine/cache.rb +4 -0
- data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
- data/lib/cyberarm_engine/common.rb +16 -16
- data/lib/cyberarm_engine/config_file.rb +46 -0
- data/lib/cyberarm_engine/game_object.rb +63 -72
- data/lib/cyberarm_engine/game_state.rb +7 -4
- data/lib/cyberarm_engine/model.rb +207 -0
- data/lib/cyberarm_engine/model/material.rb +21 -0
- data/lib/cyberarm_engine/model/model_object.rb +131 -0
- data/lib/cyberarm_engine/model/parser.rb +74 -0
- data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
- data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
- data/lib/cyberarm_engine/model_cache.rb +31 -0
- data/lib/cyberarm_engine/opengl.rb +28 -0
- data/lib/cyberarm_engine/opengl/light.rb +50 -0
- data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
- data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
- data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
- data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
- data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
- data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
- data/lib/cyberarm_engine/opengl/shader.rb +406 -0
- data/lib/cyberarm_engine/opengl/texture.rb +69 -0
- data/lib/cyberarm_engine/ray.rb +5 -5
- data/lib/cyberarm_engine/stats.rb +21 -0
- data/lib/cyberarm_engine/text.rb +45 -31
- data/lib/cyberarm_engine/timer.rb +1 -1
- data/lib/cyberarm_engine/transform.rb +221 -9
- data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
- data/lib/cyberarm_engine/ui/dsl.rb +68 -50
- data/lib/cyberarm_engine/ui/element.rb +57 -18
- data/lib/cyberarm_engine/ui/elements/button.rb +86 -16
- data/lib/cyberarm_engine/ui/elements/check_box.rb +24 -32
- data/lib/cyberarm_engine/ui/elements/container.rb +88 -24
- data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -0
- data/lib/cyberarm_engine/ui/elements/edit_line.rb +180 -27
- data/lib/cyberarm_engine/ui/elements/flow.rb +1 -3
- data/lib/cyberarm_engine/ui/elements/image.rb +12 -9
- data/lib/cyberarm_engine/ui/elements/label.rb +96 -15
- data/lib/cyberarm_engine/ui/elements/list_box.rb +68 -0
- data/lib/cyberarm_engine/ui/elements/progress.rb +6 -5
- data/lib/cyberarm_engine/ui/elements/radio.rb +6 -0
- data/lib/cyberarm_engine/ui/elements/slider.rb +104 -0
- data/lib/cyberarm_engine/ui/elements/stack.rb +1 -3
- data/lib/cyberarm_engine/ui/elements/toggle_button.rb +40 -31
- data/lib/cyberarm_engine/ui/event.rb +8 -7
- data/lib/cyberarm_engine/ui/gui_state.rb +89 -6
- data/lib/cyberarm_engine/ui/style.rb +10 -9
- data/lib/cyberarm_engine/ui/theme.rb +39 -21
- data/lib/cyberarm_engine/vector.rb +132 -38
- data/lib/cyberarm_engine/version.rb +2 -2
- data/lib/cyberarm_engine/{engine.rb → window.rb} +30 -19
- metadata +87 -16
- data/lib/cyberarm_engine/shader.rb +0 -205
@@ -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(
|
5
|
+
super(options, block)
|
6
6
|
options[:toggled] = options[:checked]
|
7
7
|
|
8
8
|
@toggle_button = ToggleButton.new(options)
|
9
9
|
@label = Label.new(text, options)
|
10
10
|
|
11
|
-
|
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.
|
28
|
-
|
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,14 +4,14 @@ 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_x, :scroll_y
|
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
|
13
|
+
@scroll_x = 0
|
14
|
+
@scroll_y = 0
|
15
15
|
@scroll_speed = 10
|
16
16
|
|
17
17
|
@text_color = options[:color]
|
@@ -22,19 +22,57 @@ module CyberarmEngine
|
|
22
22
|
def build
|
23
23
|
@block.call(self) if @block
|
24
24
|
|
25
|
-
|
25
|
+
root.gui_state.request_recalculate
|
26
26
|
end
|
27
27
|
|
28
28
|
def add(element)
|
29
29
|
@children << element
|
30
30
|
|
31
|
-
|
31
|
+
root.gui_state.request_recalculate
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear(&block)
|
35
|
+
@children.clear
|
36
|
+
|
37
|
+
old_container = $__current_container__
|
38
|
+
|
39
|
+
$__current_container__ = self
|
40
|
+
block.call(self) if block
|
41
|
+
|
42
|
+
$__current_container__ = old_container
|
43
|
+
|
44
|
+
root.gui_state.request_recalculate
|
32
45
|
end
|
33
46
|
|
34
47
|
def render
|
35
48
|
Gosu.clip_to(@x, @y, width, height) do
|
36
49
|
@children.each(&:draw)
|
37
50
|
end
|
51
|
+
|
52
|
+
if false # DEBUG
|
53
|
+
Gosu.flush
|
54
|
+
|
55
|
+
Gosu.draw_line(
|
56
|
+
x, y, Gosu::Color::RED,
|
57
|
+
x + outer_width, y, Gosu::Color::RED,
|
58
|
+
Float::INFINITY
|
59
|
+
)
|
60
|
+
Gosu.draw_line(
|
61
|
+
x + outer_width, y, Gosu::Color::RED,
|
62
|
+
x + outer_width, y + outer_height, Gosu::Color::RED,
|
63
|
+
Float::INFINITY
|
64
|
+
)
|
65
|
+
Gosu.draw_line(
|
66
|
+
x + outer_width, y + outer_height, Gosu::Color::RED,
|
67
|
+
x, y + outer_height, Gosu::Color::RED,
|
68
|
+
Float::INFINITY
|
69
|
+
)
|
70
|
+
Gosu.draw_line(
|
71
|
+
x, outer_height, Gosu::Color::RED,
|
72
|
+
x, y, Gosu::Color::RED,
|
73
|
+
Float::INFINITY
|
74
|
+
)
|
75
|
+
end
|
38
76
|
end
|
39
77
|
|
40
78
|
def update
|
@@ -43,6 +81,8 @@ module CyberarmEngine
|
|
43
81
|
|
44
82
|
def hit_element?(x, y)
|
45
83
|
@children.reverse_each do |child|
|
84
|
+
next unless child.visible?
|
85
|
+
|
46
86
|
case child
|
47
87
|
when Container
|
48
88
|
if element = child.hit_element?(x, y)
|
@@ -59,6 +99,9 @@ module CyberarmEngine
|
|
59
99
|
def recalculate
|
60
100
|
@current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
|
61
101
|
return unless visible?
|
102
|
+
|
103
|
+
Stats.increment(:gui_recalculations_last_frame, 1)
|
104
|
+
|
62
105
|
stylize
|
63
106
|
|
64
107
|
layout
|
@@ -67,24 +110,26 @@ module CyberarmEngine
|
|
67
110
|
@width = @style.width = window.width
|
68
111
|
@height = @style.height = window.height
|
69
112
|
else
|
70
|
-
@width
|
113
|
+
@width = 0
|
114
|
+
@height = 0
|
71
115
|
|
72
116
|
_width = dimensional_size(@style.width, :width)
|
73
|
-
_height= dimensional_size(@style.height
|
117
|
+
_height = dimensional_size(@style.height, :height)
|
74
118
|
|
75
|
-
@width = _width
|
76
|
-
@height = _height
|
119
|
+
@width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).round
|
120
|
+
@height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).round
|
77
121
|
end
|
78
122
|
|
79
|
-
|
80
123
|
# Move child to parent after positioning
|
81
124
|
@children.each do |child|
|
82
|
-
child.x += @x
|
83
|
-
child.y += @y
|
125
|
+
child.x += (@x + @style.border_thickness_left) - style.margin_left
|
126
|
+
child.y += (@y + @style.border_thickness_top) - style.margin_top
|
84
127
|
|
85
128
|
child.stylize
|
86
129
|
child.recalculate
|
87
130
|
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
|
131
|
+
|
132
|
+
Stats.increment(:gui_recalculations_last_frame, 1)
|
88
133
|
end
|
89
134
|
|
90
135
|
update_background
|
@@ -95,32 +140,36 @@ module CyberarmEngine
|
|
95
140
|
end
|
96
141
|
|
97
142
|
def max_width
|
98
|
-
|
143
|
+
_width = dimensional_size(@style.width, :width)
|
144
|
+
if _width
|
145
|
+
outer_width
|
146
|
+
else
|
147
|
+
window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
|
148
|
+
end
|
99
149
|
end
|
100
150
|
|
101
151
|
def fits_on_line?(element) # Flow
|
152
|
+
p [@options[:id], @width] if @options[:id]
|
102
153
|
@current_position.x + element.outer_width <= max_width &&
|
103
|
-
|
154
|
+
@current_position.x + element.outer_width <= window.width
|
104
155
|
end
|
105
156
|
|
106
157
|
def position_on_current_line(element) # Flow
|
107
158
|
element.x = element.style.margin_left + @current_position.x
|
108
159
|
element.y = element.style.margin_top + @current_position.y
|
109
160
|
|
110
|
-
element.recalculate
|
111
|
-
|
112
161
|
@current_position.x += element.outer_width
|
113
162
|
@current_position.x = @style.margin_left if @current_position.x >= max_width
|
114
163
|
end
|
115
164
|
|
116
|
-
def tallest_neighbor(querier,
|
165
|
+
def tallest_neighbor(querier, _y_position) # Flow
|
117
166
|
response = querier
|
118
167
|
@children.each do |child|
|
119
168
|
response = child if child.outer_height > response.outer_height
|
120
169
|
break if child == querier
|
121
170
|
end
|
122
171
|
|
123
|
-
|
172
|
+
response
|
124
173
|
end
|
125
174
|
|
126
175
|
def position_on_next_line(child) # Flow
|
@@ -130,8 +179,6 @@ module CyberarmEngine
|
|
130
179
|
child.x = child.style.margin_left + @current_position.x
|
131
180
|
child.y = child.style.margin_top + @current_position.y
|
132
181
|
|
133
|
-
child.recalculate
|
134
|
-
|
135
182
|
@current_position.x += child.outer_width
|
136
183
|
end
|
137
184
|
|
@@ -139,8 +186,6 @@ module CyberarmEngine
|
|
139
186
|
element.x = element.style.margin_left + @current_position.x
|
140
187
|
element.y = element.style.margin_top + @current_position.y
|
141
188
|
|
142
|
-
element.recalculate
|
143
|
-
|
144
189
|
@current_position.y += element.outer_height
|
145
190
|
end
|
146
191
|
|
@@ -155,8 +200,27 @@ module CyberarmEngine
|
|
155
200
|
# end
|
156
201
|
|
157
202
|
def value
|
158
|
-
@children.map {|c| c.class}.join(", ")
|
203
|
+
@children.map { |c| c.class }.join(", ")
|
204
|
+
end
|
205
|
+
|
206
|
+
def to_s
|
207
|
+
"#{self.class} x=#{x} y=#{y} width=#{width} height=#{height} children=#{@children.size}"
|
208
|
+
end
|
209
|
+
|
210
|
+
def write_tree(indent = "", _index = 0)
|
211
|
+
puts self
|
212
|
+
|
213
|
+
indent += " "
|
214
|
+
@children.each_with_index do |child, i|
|
215
|
+
print "#{indent}#{i}: "
|
216
|
+
|
217
|
+
if child.is_a?(Container)
|
218
|
+
child.write_tree(indent)
|
219
|
+
else
|
220
|
+
puts child
|
221
|
+
end
|
222
|
+
end
|
159
223
|
end
|
160
224
|
end
|
161
225
|
end
|
162
|
-
end
|
226
|
+
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
|