cyberarm_engine 0.23.0 → 0.24.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/assets/shaders/fragment/g_buffer.glsl +8 -8
- data/assets/shaders/fragment/lighting.glsl +15 -9
- data/assets/shaders/include/material_struct.glsl +16 -0
- data/assets/shaders/vertex/g_buffer.glsl +17 -17
- data/assets/shaders/vertex/lighting.glsl +16 -9
- data/lib/cyberarm_engine/builtin/intro_state.rb +1 -1
- data/lib/cyberarm_engine/common.rb +2 -2
- data/lib/cyberarm_engine/console.rb +10 -10
- data/lib/cyberarm_engine/game_object.rb +1 -1
- data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +98 -0
- data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +31 -0
- data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -0
- data/lib/cyberarm_engine/model.rb +7 -6
- data/lib/cyberarm_engine/notification.rb +83 -0
- data/lib/cyberarm_engine/notification_manager.rb +242 -0
- data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +16 -10
- data/lib/cyberarm_engine/opengl/renderer/renderer.rb +12 -1
- data/lib/cyberarm_engine/opengl/shader.rb +2 -2
- data/lib/cyberarm_engine/stats.rb +181 -10
- data/lib/cyberarm_engine/text.rb +3 -0
- data/lib/cyberarm_engine/ui/element.rb +45 -14
- data/lib/cyberarm_engine/ui/elements/container.rb +86 -27
- data/lib/cyberarm_engine/ui/elements/slider.rb +4 -3
- data/lib/cyberarm_engine/ui/elements/text_block.rb +11 -1
- data/lib/cyberarm_engine/ui/gui_state.rb +28 -18
- data/lib/cyberarm_engine/ui/style.rb +2 -1
- data/lib/cyberarm_engine/vector.rb +35 -16
- data/lib/cyberarm_engine/version.rb +1 -1
- data/lib/cyberarm_engine/window.rb +35 -8
- data/lib/cyberarm_engine.rb +8 -2
- data/mrbgem.rake +29 -0
- metadata +10 -3
@@ -0,0 +1,242 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
class NotificationManager
|
3
|
+
EDGE_TOP = :top
|
4
|
+
EDGE_BOTTOM = :bottom
|
5
|
+
EDGE_RIGHT = :right
|
6
|
+
EDGE_LEFT = :left
|
7
|
+
|
8
|
+
MODE_DEFAULT = :slide
|
9
|
+
MODE_CIRCLE = :circle
|
10
|
+
|
11
|
+
attr_reader :edge, :mode, :max_visible, :notifications
|
12
|
+
def initialize(edge: EDGE_RIGHT, mode: MODE_DEFAULT, window:, max_visible: 1)
|
13
|
+
@edge = edge
|
14
|
+
@mode = mode
|
15
|
+
@window = window
|
16
|
+
@max_visible = max_visible
|
17
|
+
|
18
|
+
@notifications = []
|
19
|
+
@drivers = []
|
20
|
+
@slots = Array.new(max_visible, nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
def draw
|
24
|
+
@drivers.each do |driver|
|
25
|
+
case @edge
|
26
|
+
when :left, :right
|
27
|
+
x = @edge == :right ? @window.width + driver.x : -Notification::WIDTH + driver.x
|
28
|
+
y = driver.y + Notification::HEIGHT / 2
|
29
|
+
|
30
|
+
Gosu.translate(x, y + (Notification::HEIGHT + Notification::PADDING) * driver.slot) do
|
31
|
+
driver.draw
|
32
|
+
end
|
33
|
+
|
34
|
+
when :top, :bottom
|
35
|
+
x = @window.width / 2 - Notification::WIDTH / 2
|
36
|
+
y = @edge == :top ? driver.y - Notification::HEIGHT : @window.height + driver.y
|
37
|
+
slot_position = (Notification::HEIGHT + Notification::PADDING) * driver.slot
|
38
|
+
slot_position *= -1 if @edge == :bottom
|
39
|
+
|
40
|
+
Gosu.translate(x, y + slot_position) do
|
41
|
+
driver.draw
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def update
|
48
|
+
show_next_notification if @drivers.size < @max_visible
|
49
|
+
@drivers.each do |driver|
|
50
|
+
if driver.done?
|
51
|
+
@slots[driver.slot] = nil
|
52
|
+
@drivers.delete(driver)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@drivers.each(&:update)
|
57
|
+
end
|
58
|
+
|
59
|
+
def show_next_notification
|
60
|
+
notification = @notifications.sort { |n| n.priority }.reverse.shift
|
61
|
+
return unless notification
|
62
|
+
return if available_slot_index < lowest_used_slot
|
63
|
+
@notifications.delete(notification)
|
64
|
+
|
65
|
+
@drivers << Driver.new(edge: @edge, mode: @mode, notification: notification, slot: available_slot_index)
|
66
|
+
slot = @slots[available_slot_index] = @drivers.last
|
67
|
+
end
|
68
|
+
|
69
|
+
def available_slot_index
|
70
|
+
@slots.each_with_index do |slot, i|
|
71
|
+
return i unless slot
|
72
|
+
end
|
73
|
+
|
74
|
+
return -1
|
75
|
+
end
|
76
|
+
|
77
|
+
def lowest_used_slot
|
78
|
+
@slots.each_with_index do |slot, i|
|
79
|
+
return i if slot
|
80
|
+
end
|
81
|
+
|
82
|
+
return -1
|
83
|
+
end
|
84
|
+
|
85
|
+
def highest_used_slot
|
86
|
+
_slot = -1
|
87
|
+
@slots.each_with_index do |slot, i|
|
88
|
+
_slot = i if slot
|
89
|
+
end
|
90
|
+
|
91
|
+
return _slot
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_notification(**args)
|
95
|
+
notification = Notification.new(host: self, **args)
|
96
|
+
@notifications << notification
|
97
|
+
end
|
98
|
+
|
99
|
+
class Driver
|
100
|
+
attr_reader :x, :y, :notification, :slot
|
101
|
+
def initialize(edge:, mode:, notification:, slot:)
|
102
|
+
@edge = edge
|
103
|
+
@mode = mode
|
104
|
+
@notification = notification
|
105
|
+
@slot = slot
|
106
|
+
|
107
|
+
@x, @y = 0, 0
|
108
|
+
@delta = Gosu.milliseconds
|
109
|
+
@accumulator = 0.0
|
110
|
+
|
111
|
+
@born_at = Gosu.milliseconds
|
112
|
+
@duration_completed_at = Float::INFINITY
|
113
|
+
@transition_completed_at = Float::INFINITY
|
114
|
+
end
|
115
|
+
|
116
|
+
def transition_in_complete?
|
117
|
+
Gosu.milliseconds - @born_at >= @notification.transition_duration
|
118
|
+
end
|
119
|
+
|
120
|
+
def duration_completed?
|
121
|
+
Gosu.milliseconds - @transition_completed_at >= @notification.time_to_live
|
122
|
+
end
|
123
|
+
|
124
|
+
def done?
|
125
|
+
Gosu.milliseconds - @duration_completed_at >= @notification.transition_duration
|
126
|
+
end
|
127
|
+
|
128
|
+
def draw
|
129
|
+
ratio = 0.0
|
130
|
+
|
131
|
+
if not transition_in_complete?
|
132
|
+
ratio = animation_ratio
|
133
|
+
elsif transition_in_complete? and not duration_completed?
|
134
|
+
ratio = 1.0
|
135
|
+
elsif duration_completed?
|
136
|
+
ratio = 1.0 - animation_ratio
|
137
|
+
end
|
138
|
+
|
139
|
+
case @mode
|
140
|
+
when MODE_DEFAULT
|
141
|
+
Gosu.clip_to(0, 0, Notification::WIDTH, Notification::HEIGHT * ratio) do
|
142
|
+
@notification.draw
|
143
|
+
end
|
144
|
+
when MODE_CIRCLE
|
145
|
+
half = Notification::WIDTH / 2
|
146
|
+
|
147
|
+
Gosu.clip_to(half - (half * ratio), 0, Notification::WIDTH * ratio, Notification::HEIGHT) do
|
148
|
+
@notification.draw
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def update
|
154
|
+
case @mode
|
155
|
+
when MODE_DEFAULT
|
156
|
+
update_default
|
157
|
+
when MODE_CIRCLE
|
158
|
+
update_circle
|
159
|
+
end
|
160
|
+
|
161
|
+
@accumulator += Gosu.milliseconds - @delta
|
162
|
+
@delta = Gosu.milliseconds
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
def update_default
|
167
|
+
case @edge
|
168
|
+
when :left, :right
|
169
|
+
if not transition_in_complete? # Slide In
|
170
|
+
@x = @edge == :right ? -x_offset : x_offset
|
171
|
+
elsif transition_in_complete? and not duration_completed?
|
172
|
+
@x = @edge == :right ? -Notification::WIDTH : Notification::WIDTH if @x.abs != Notification::WIDTH
|
173
|
+
@transition_completed_at = Gosu.milliseconds if @transition_completed_at == Float::INFINITY
|
174
|
+
@accumulator = 0.0
|
175
|
+
elsif duration_completed? # Slide Out
|
176
|
+
@x = @edge == :right ? x_offset - Notification::WIDTH : Notification::WIDTH - x_offset
|
177
|
+
@x = 0 if @edge == :left and @x <= 0
|
178
|
+
@x = 0 if @edge == :right and @x >= 0
|
179
|
+
@duration_completed_at = Gosu.milliseconds if @duration_completed_at == Float::INFINITY
|
180
|
+
end
|
181
|
+
|
182
|
+
when :top, :bottom
|
183
|
+
if not transition_in_complete? # Slide In
|
184
|
+
@y = @edge == :top ? y_offset : -y_offset
|
185
|
+
elsif transition_in_complete? and not duration_completed?
|
186
|
+
@y = @edge == :top ? Notification::HEIGHT : -Notification::HEIGHT if @x.abs != Notification::HEIGHT
|
187
|
+
@transition_completed_at = Gosu.milliseconds if @transition_completed_at == Float::INFINITY
|
188
|
+
@accumulator = 0.0
|
189
|
+
elsif duration_completed? # Slide Out
|
190
|
+
@y = @edge == :top ? Notification::HEIGHT - y_offset : y_offset - Notification::HEIGHT
|
191
|
+
@y = 0 if @edge == :top and @y <= 0
|
192
|
+
@y = 0 if @edge == :bottom and @y >= 0
|
193
|
+
@duration_completed_at = Gosu.milliseconds if @duration_completed_at == Float::INFINITY
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def update_circle
|
199
|
+
case @edge
|
200
|
+
when :top, :bottom
|
201
|
+
@y = @edge == :top ? Notification::HEIGHT : -Notification::HEIGHT
|
202
|
+
when :left, :right
|
203
|
+
@x = @edge == :right ? -Notification::WIDTH : Notification::WIDTH
|
204
|
+
end
|
205
|
+
|
206
|
+
if transition_in_complete? and not duration_completed?
|
207
|
+
@transition_completed_at = Gosu.milliseconds if @transition_completed_at == Float::INFINITY
|
208
|
+
@accumulator = 0.0
|
209
|
+
elsif duration_completed?
|
210
|
+
@duration_completed_at = Gosu.milliseconds if @duration_completed_at == Float::INFINITY
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def animation_ratio
|
215
|
+
x = (@accumulator / @notification.transition_duration)
|
216
|
+
|
217
|
+
case @notification.transition_type
|
218
|
+
when Notification::LINEAR_TRANSITION
|
219
|
+
x.clamp(0.0, 1.0)
|
220
|
+
when Notification::EASE_IN_OUT_TRANSITION # https://easings.net/#easeInOutQuint
|
221
|
+
(x < 0.5 ? 16 * x * x * x * x * x : 1 - ((-2 * x + 2) ** 5) / 2).clamp(0.0, 1.0)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def x_offset
|
226
|
+
if not transition_in_complete? or duration_completed?
|
227
|
+
Notification::WIDTH * animation_ratio
|
228
|
+
else
|
229
|
+
0
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def y_offset
|
234
|
+
if not transition_in_complete? or duration_completed?
|
235
|
+
Notification::HEIGHT * animation_ratio
|
236
|
+
else
|
237
|
+
0
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -44,7 +44,7 @@ module CyberarmEngine
|
|
44
44
|
shader.uniform_transform("projection", camera.projection_matrix)
|
45
45
|
shader.uniform_transform("view", camera.view_matrix)
|
46
46
|
shader.uniform_transform("model", entity.model_matrix)
|
47
|
-
shader.
|
47
|
+
shader.uniform_vector3("camera_position", camera.position)
|
48
48
|
|
49
49
|
gl_error?
|
50
50
|
draw_model(entity.model, shader)
|
@@ -154,15 +154,21 @@ module CyberarmEngine
|
|
154
154
|
glBindTexture(GL_TEXTURE_2D, @g_buffer.texture(:depth))
|
155
155
|
shader.uniform_integer("depth", 4)
|
156
156
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
shader.uniform_vec3("light[0].ambient", light.ambient)
|
163
|
-
shader.uniform_vec3("light[0].specular", light.specular)
|
157
|
+
# FIXME: Try to figure out how to up this to 32 and/or beyond
|
158
|
+
# (currently fails with more then 7 lights passed in to shader)
|
159
|
+
lights.each_slice(7).each do |light_group|
|
160
|
+
light_group.each_with_index do |light, _i|
|
161
|
+
shader.uniform_integer("light_count", light_group.size)
|
164
162
|
|
165
|
-
|
163
|
+
shader.uniform_integer("lights[#{_i}].type", light.type)
|
164
|
+
shader.uniform_vector3("lights[#{_i}].direction", light.direction)
|
165
|
+
shader.uniform_vector3("lights[#{_i}].position", light.position)
|
166
|
+
shader.uniform_vector3("lights[#{_i}].diffuse", light.diffuse)
|
167
|
+
shader.uniform_vector3("lights[#{_i}].ambient", light.ambient)
|
168
|
+
shader.uniform_vector3("lights[#{_i}].specular", light.specular)
|
169
|
+
|
170
|
+
glDrawArrays(GL_TRIANGLES, 0, @g_buffer.vertices.size)
|
171
|
+
end
|
166
172
|
end
|
167
173
|
|
168
174
|
glBindVertexArray(0)
|
@@ -215,7 +221,7 @@ module CyberarmEngine
|
|
215
221
|
|
216
222
|
offset = 0
|
217
223
|
model.objects.each do |object|
|
218
|
-
shader.uniform_boolean("
|
224
|
+
shader.uniform_boolean("has_texture", object.has_texture?)
|
219
225
|
|
220
226
|
if object.has_texture?
|
221
227
|
glBindTexture(GL_TEXTURE_2D, object.materials.find { |mat| mat.texture_id }.texture_id)
|
@@ -8,8 +8,19 @@ module CyberarmEngine
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def draw(camera, lights, entities)
|
11
|
+
Stats.frame.start_timing(:opengl_renderer)
|
12
|
+
|
13
|
+
Stats.frame.start_timing(:opengl_model_renderer)
|
11
14
|
@opengl_renderer.render(camera, lights, entities)
|
12
|
-
|
15
|
+
Stats.frame.end_timing(:opengl_model_renderer)
|
16
|
+
|
17
|
+
if @show_bounding_boxes
|
18
|
+
Stats.frame.start_timing(:opengl_boundingbox_renderer)
|
19
|
+
@bounding_box_renderer.render(entities)
|
20
|
+
Stats.frame.end_timing(:opengl_boundingbox_renderer)
|
21
|
+
end
|
22
|
+
|
23
|
+
Stats.frame.end_timing(:opengl_renderer)
|
13
24
|
end
|
14
25
|
|
15
26
|
def canvas_size_changed
|
@@ -385,7 +385,7 @@ module CyberarmEngine
|
|
385
385
|
# @param value [Vector]
|
386
386
|
# @param location [Integer]
|
387
387
|
# @return [void]
|
388
|
-
def
|
388
|
+
def uniform_vector3(variable, value, location = nil)
|
389
389
|
attr_loc = location || attribute_location(variable)
|
390
390
|
|
391
391
|
glUniform3f(attr_loc, *value.to_a[0..2])
|
@@ -397,7 +397,7 @@ module CyberarmEngine
|
|
397
397
|
# @param value [Vector]
|
398
398
|
# @param location [Integer]
|
399
399
|
# @return [void]
|
400
|
-
def
|
400
|
+
def uniform_vector4(variable, value, location = nil)
|
401
401
|
attr_loc = location || attribute_location(variable)
|
402
402
|
|
403
403
|
glUniform4f(attr_loc, *value.to_a)
|
@@ -1,20 +1,191 @@
|
|
1
1
|
module CyberarmEngine
|
2
2
|
class Stats
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
@frames = []
|
4
|
+
@frame_index = -1
|
5
|
+
@max_frame_history = 1024
|
6
6
|
|
7
|
-
def self.
|
8
|
-
|
7
|
+
def self.new_frame
|
8
|
+
if @frames.size < @max_frame_history
|
9
|
+
@frames << Frame.new
|
10
|
+
else
|
11
|
+
@frames[@frame_index] = Frame.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.frame
|
16
|
+
@frames[@frame_index]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.end_frame
|
20
|
+
frame&.complete
|
21
|
+
|
22
|
+
@frame_index += 1
|
23
|
+
@frame_index %= @max_frame_history
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.frames
|
27
|
+
if @frames.size < @max_frame_history
|
28
|
+
@frames
|
29
|
+
else
|
30
|
+
@frames.rotate(@frame_index - (@max_frame_history - (@frames.size - 1)))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.frame_index
|
35
|
+
@frame_index
|
9
36
|
end
|
10
37
|
|
11
|
-
def self.
|
12
|
-
|
38
|
+
def self.max_frame_history
|
39
|
+
@max_frame_history
|
13
40
|
end
|
14
41
|
|
15
|
-
|
16
|
-
|
17
|
-
|
42
|
+
class Frame
|
43
|
+
Timing = Struct.new(:start_time, :end_time, :duration)
|
44
|
+
|
45
|
+
attr_reader :frame_timing, :counters, :timings, :multitimings
|
46
|
+
def initialize
|
47
|
+
@frame_timing = Timing.new(Gosu.milliseconds, -1, -1)
|
48
|
+
@attempted_multitiming = false
|
49
|
+
|
50
|
+
@counters = {
|
51
|
+
gui_recalculations: 0
|
52
|
+
}
|
53
|
+
|
54
|
+
@timings = {}
|
55
|
+
@multitimings = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def increment(key, number = 1)
|
59
|
+
@counters[key] ||= 0
|
60
|
+
@counters[key] += number
|
61
|
+
end
|
62
|
+
|
63
|
+
def start_timing(key)
|
64
|
+
raise "key must be a symbol!" unless key.is_a?(Symbol)
|
65
|
+
if @timings[key]
|
66
|
+
# FIXME: Make it not spammy...
|
67
|
+
# warn "Only one timing per key per frame. (Timing for #{key.inspect} already exists!)"
|
68
|
+
@attempted_multitiming = true
|
69
|
+
@multitimings[key] = true
|
70
|
+
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
@timings[key] = Timing.new(Gosu.milliseconds, -1, -1)
|
75
|
+
end
|
76
|
+
|
77
|
+
def end_timing(key)
|
78
|
+
timing = @timings[key]
|
79
|
+
|
80
|
+
# FIXME: Make it not spammy...
|
81
|
+
# warn "Timing #{key.inspect} already ended!" if timing.end_time != -1
|
82
|
+
|
83
|
+
timing.end_time = Gosu.milliseconds
|
84
|
+
timing.duration = timing.end_time - timing.start_time
|
85
|
+
end
|
86
|
+
|
87
|
+
def complete
|
88
|
+
@frame_timing.end_time = Gosu.milliseconds
|
89
|
+
@frame_timing.duration = @frame_timing.end_time - @frame_timing.start_time
|
90
|
+
|
91
|
+
# Lock data structures
|
92
|
+
@frame_timing.freeze
|
93
|
+
@counters.freeze
|
94
|
+
@timings.freeze
|
95
|
+
@multitimings.freeze
|
96
|
+
end
|
97
|
+
|
98
|
+
def complete?
|
99
|
+
@frame_timing.duration != -1
|
100
|
+
end
|
101
|
+
|
102
|
+
def attempted_multitiming?
|
103
|
+
@attempted_multitiming
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class StatsPlotter
|
108
|
+
attr_reader :position
|
109
|
+
|
110
|
+
def initialize(x, y, z = Float::INFINITY, width = 128, height = 128)
|
111
|
+
@position = Vector.new(x, y, z)
|
112
|
+
@width = width
|
113
|
+
@height = height
|
114
|
+
|
115
|
+
@padding = 2
|
116
|
+
@text_size = 16
|
117
|
+
|
118
|
+
@max_timing_label = CyberarmEngine::Text.new("", x: x + @padding + 1, y: y + @padding, z: z, size: @text_size, border: true)
|
119
|
+
@avg_timing_label = CyberarmEngine::Text.new("", x: x + @padding + 1, y: y + @padding + @height / 2 - @text_size / 2, z: z, size: @text_size, border: true)
|
120
|
+
@min_timing_label = CyberarmEngine::Text.new("", x: x + @padding + 1, y: y + @height - (@text_size + @padding / 2), z: z, size: @text_size, border: true)
|
121
|
+
|
122
|
+
@timings_label = CyberarmEngine::Text.new("", x: x + @padding + @width + @padding, y: y + @padding, z: z, size: @text_size, border: true)
|
123
|
+
|
124
|
+
@frame_stats = []
|
125
|
+
@graphs = {
|
126
|
+
frame_timings: []
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def calculate_graphs
|
131
|
+
calculate_frame_timings_graph
|
132
|
+
end
|
133
|
+
|
134
|
+
def calculate_frame_timings_graph
|
135
|
+
@graphs[:frame_timings].clear
|
136
|
+
|
137
|
+
samples = @width - @padding
|
138
|
+
nodes = Array.new(samples.ceil) { [] }
|
139
|
+
|
140
|
+
slice = 0
|
141
|
+
@frame_stats.each_slice((CyberarmEngine::Stats.max_frame_history / samples.to_f).ceil) do |bucket|
|
142
|
+
bucket.each do |frame|
|
143
|
+
nodes[slice] << frame.frame_timing.duration
|
144
|
+
end
|
145
|
+
|
146
|
+
slice += 1
|
147
|
+
end
|
148
|
+
|
149
|
+
nodes.each_with_index do |cluster, i|
|
150
|
+
break if cluster.empty?
|
151
|
+
|
152
|
+
@graphs[:frame_timings] << CyberarmEngine::Vector.new(@position.x + @padding + 1 * i, (@position.y + @height - @padding) - cluster.max)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def draw
|
157
|
+
@frame_stats = CyberarmEngine::Stats.frames.select(&:complete?)
|
158
|
+
return if @frame_stats.empty?
|
159
|
+
|
160
|
+
calculate_graphs
|
161
|
+
|
162
|
+
@max_timing_label.text = "Max: #{@frame_stats.map { |f| f.frame_timing.duration }.max.to_s.rjust(3, " ")}ms"
|
163
|
+
@avg_timing_label.text = "Avg: #{(@frame_stats.map { |f| f.frame_timing.duration }.sum / @frame_stats.size).to_s.rjust(3, " ")}ms"
|
164
|
+
@min_timing_label.text = "Min: #{@frame_stats.map { |f| f.frame_timing.duration }.min.to_s.rjust(3, " ")}ms"
|
165
|
+
|
166
|
+
Gosu.draw_rect(@position.x, @position.y, @width, @height, 0xaa_222222, @position.z)
|
167
|
+
Gosu.draw_rect(@position.x + @padding, @position.y + @padding, @width - @padding * 2, @height - @padding * 2, 0xaa_222222, @position.z)
|
168
|
+
|
169
|
+
draw_graphs
|
170
|
+
|
171
|
+
@max_timing_label.draw
|
172
|
+
@avg_timing_label.draw
|
173
|
+
@min_timing_label.draw
|
174
|
+
|
175
|
+
# TODO: Make this optional
|
176
|
+
draw_timings
|
177
|
+
end
|
178
|
+
|
179
|
+
def draw_graphs
|
180
|
+
Gosu.draw_path(@graphs[:frame_timings], Gosu::Color::WHITE, Float::INFINITY)
|
181
|
+
end
|
182
|
+
|
183
|
+
def draw_timings
|
184
|
+
frame = @frame_stats.last
|
185
|
+
|
186
|
+
@timings_label.text = "#{frame.attempted_multitiming? ? "<c=d00>Attempted Multitiming!\nTimings may be inaccurate for:\n#{frame.multitimings.map { |m, _| m}.join("\n") }</c>\n\n" : ''}#{frame.timings.map { |t, v| "#{t}: #{v.duration}ms" }.join("\n")}"
|
187
|
+
Gosu.draw_rect(@timings_label.x - @padding, @timings_label.y - @padding, @timings_label.width + @padding * 2, @timings_label.height + @padding * 2, 0xdd_222222, @position.z)
|
188
|
+
@timings_label.draw
|
18
189
|
end
|
19
190
|
end
|
20
191
|
end
|
data/lib/cyberarm_engine/text.rb
CHANGED
@@ -81,6 +81,7 @@ module CyberarmEngine
|
|
81
81
|
@size = size
|
82
82
|
@font = font_name
|
83
83
|
|
84
|
+
invalidate_cache!
|
84
85
|
@textobject = check_cache(size, font_name)
|
85
86
|
end
|
86
87
|
end
|
@@ -149,6 +150,8 @@ module CyberarmEngine
|
|
149
150
|
end
|
150
151
|
|
151
152
|
def markup_width(text = @text)
|
153
|
+
text = text.to_s
|
154
|
+
|
152
155
|
spacing = 0
|
153
156
|
spacing += @border_size if @border
|
154
157
|
spacing += @shadow_size if @shadow
|
@@ -30,6 +30,8 @@ module CyberarmEngine
|
|
30
30
|
@y = @style.y
|
31
31
|
@z = @style.z
|
32
32
|
|
33
|
+
@old_width = 0
|
34
|
+
@old_height = 0
|
33
35
|
@width = 0
|
34
36
|
@height = 0
|
35
37
|
|
@@ -196,7 +198,7 @@ module CyberarmEngine
|
|
196
198
|
end
|
197
199
|
|
198
200
|
def enter(_sender)
|
199
|
-
@focus = false unless
|
201
|
+
@focus = false unless Gosu.button_down?(Gosu::MS_LEFT)
|
200
202
|
|
201
203
|
if !@enabled
|
202
204
|
update_styles(:disabled)
|
@@ -316,7 +318,8 @@ module CyberarmEngine
|
|
316
318
|
end
|
317
319
|
|
318
320
|
def debug_draw
|
319
|
-
|
321
|
+
# FIXME
|
322
|
+
return# if const_defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
|
320
323
|
|
321
324
|
Gosu.draw_line(
|
322
325
|
x, y, @debug_color,
|
@@ -341,6 +344,7 @@ module CyberarmEngine
|
|
341
344
|
end
|
342
345
|
|
343
346
|
def update
|
347
|
+
recalculate_if_size_changed
|
344
348
|
end
|
345
349
|
|
346
350
|
def button_down(id)
|
@@ -410,10 +414,14 @@ module CyberarmEngine
|
|
410
414
|
end
|
411
415
|
|
412
416
|
def scroll_width
|
413
|
-
@
|
417
|
+
return @cached_scroll_width if @cached_scroll_width && is_a?(Container)
|
418
|
+
|
419
|
+
@cached_scroll_width = @children.sum(&:outer_width)
|
414
420
|
end
|
415
421
|
|
416
422
|
def scroll_height
|
423
|
+
return @cached_scroll_height if @cached_scroll_height && is_a?(Container)
|
424
|
+
|
417
425
|
if is_a?(CyberarmEngine::Element::Flow)
|
418
426
|
return 0 if @children.size.zero?
|
419
427
|
|
@@ -434,18 +442,18 @@ module CyberarmEngine
|
|
434
442
|
|
435
443
|
pairs_ << a_ unless pairs_.last == a_
|
436
444
|
|
437
|
-
pairs_.sum { |pair| + @style.padding_top + @style.border_thickness_top + pair.map(&:outer_height).max } + @style.padding_bottom + @style.border_thickness_bottom
|
445
|
+
@cached_scroll_height = pairs_.sum { |pair| + @style.padding_top + @style.border_thickness_top + pair.map(&:outer_height).max } + @style.padding_bottom + @style.border_thickness_bottom
|
438
446
|
else
|
439
|
-
@style.padding_top + @style.border_thickness_top + @children.sum(&:outer_height) + @style.padding_bottom + @style.border_thickness_bottom
|
447
|
+
@cached_scroll_height = @style.padding_top + @style.border_thickness_top + @children.sum(&:outer_height) + @style.padding_bottom + @style.border_thickness_bottom
|
440
448
|
end
|
441
449
|
end
|
442
450
|
|
443
451
|
def max_scroll_width
|
444
|
-
scroll_width - outer_width
|
452
|
+
(scroll_width - outer_width).positive? ? scroll_width - outer_width : scroll_width
|
445
453
|
end
|
446
454
|
|
447
455
|
def max_scroll_height
|
448
|
-
scroll_height - outer_height
|
456
|
+
(scroll_height - outer_height).positive? ? scroll_height - outer_height : scroll_height
|
449
457
|
end
|
450
458
|
|
451
459
|
def dimensional_size(size, dimension)
|
@@ -461,15 +469,13 @@ module CyberarmEngine
|
|
461
469
|
if @parent && @style.fill &&
|
462
470
|
(dimension == :width && @parent.is_a?(Flow) ||
|
463
471
|
dimension == :height && @parent.is_a?(Stack))
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
# Handle min_width/height and max_width/height
|
468
|
-
else
|
469
|
-
return @style.send(:"min_#{dimension}") if @style.send(:"min_#{dimension}") && new_size.to_f < @style.send(:"min_#{dimension}")
|
470
|
-
return @style.send(:"max_#{dimension}") if @style.send(:"max_#{dimension}") && new_size.to_f > @style.send(:"max_#{dimension}")
|
472
|
+
new_size = space_available_width - noncontent_width if dimension == :width && @parent.is_a?(Flow)
|
473
|
+
new_size = space_available_height - noncontent_height if dimension == :height && @parent.is_a?(Stack)
|
471
474
|
end
|
472
475
|
|
476
|
+
return @style.send(:"min_#{dimension}") if @style.send(:"min_#{dimension}") && new_size.to_f < @style.send(:"min_#{dimension}")
|
477
|
+
return @style.send(:"max_#{dimension}") if @style.send(:"max_#{dimension}") && new_size.to_f > @style.send(:"max_#{dimension}")
|
478
|
+
|
473
479
|
new_size
|
474
480
|
end
|
475
481
|
|
@@ -555,6 +561,15 @@ module CyberarmEngine
|
|
555
561
|
@style.background_image_canvas.image = @style.background_image
|
556
562
|
end
|
557
563
|
|
564
|
+
def recalculate_if_size_changed
|
565
|
+
if !is_a?(ToolTip) && (@old_width != width || @old_height != height)
|
566
|
+
root.gui_state.request_recalculate
|
567
|
+
|
568
|
+
@old_width = width
|
569
|
+
@old_height = height
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
558
573
|
def root
|
559
574
|
return self if is_root?
|
560
575
|
|
@@ -575,6 +590,22 @@ module CyberarmEngine
|
|
575
590
|
@gui_state != nil
|
576
591
|
end
|
577
592
|
|
593
|
+
def child_of?(element)
|
594
|
+
return element == self if is_root?
|
595
|
+
return false unless element.is_a?(Container)
|
596
|
+
return true if element.children.find { |child| child == self }
|
597
|
+
|
598
|
+
element.children.find { |child| child.child_of?(element) if child.is_a?(Container) }
|
599
|
+
end
|
600
|
+
|
601
|
+
def parent_of?(element)
|
602
|
+
return false if element == self
|
603
|
+
return false unless is_a?(Container)
|
604
|
+
return true if @children.find { |child| child == element }
|
605
|
+
|
606
|
+
@children.find { |child| child.parent_of?(element) if child.is_a?(Container) }
|
607
|
+
end
|
608
|
+
|
578
609
|
def focus(_)
|
579
610
|
warn "#{self.class}#focus was not overridden!"
|
580
611
|
|