cyberarm_engine 0.22.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 +30 -0
- data/assets/shaders/fragment/lighting.glsl +69 -0
- data/assets/shaders/include/light_struct.glsl +11 -0
- data/assets/shaders/include/material_struct.glsl +16 -0
- data/assets/shaders/vertex/g_buffer.glsl +28 -0
- data/assets/shaders/vertex/lighting.glsl +24 -0
- data/lib/cyberarm_engine/background_image.rb +1 -1
- data/lib/cyberarm_engine/builtin/intro_state.rb +3 -3
- data/lib/cyberarm_engine/common.rb +14 -2
- data/lib/cyberarm_engine/console.rb +10 -10
- data/lib/cyberarm_engine/game_object.rb +1 -1
- data/lib/cyberarm_engine/game_state.rb +4 -0
- 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/g_buffer.rb +1 -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/opengl.rb +13 -1
- data/lib/cyberarm_engine/stats.rb +181 -10
- data/lib/cyberarm_engine/text.rb +3 -0
- data/lib/cyberarm_engine/ui/border_canvas.rb +2 -2
- data/lib/cyberarm_engine/ui/element.rb +74 -26
- data/lib/cyberarm_engine/ui/elements/container.rb +95 -25
- data/lib/cyberarm_engine/ui/elements/edit_line.rb +6 -0
- data/lib/cyberarm_engine/ui/elements/image.rb +2 -2
- data/lib/cyberarm_engine/ui/elements/progress.rb +5 -0
- data/lib/cyberarm_engine/ui/elements/slider.rb +6 -3
- data/lib/cyberarm_engine/ui/elements/text_block.rb +19 -1
- data/lib/cyberarm_engine/ui/gui_state.rb +53 -27
- 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 +40 -8
- data/lib/cyberarm_engine.rb +8 -2
- data/mrbgem.rake +29 -0
- metadata +15 -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)
|
@@ -11,7 +11,19 @@ module CyberarmEngine
|
|
11
11
|
if e != GL_NO_ERROR
|
12
12
|
warn "OpenGL error detected by handler at: #{caller[0]}"
|
13
13
|
warn " #{gluErrorString(e)} (#{e})\n"
|
14
|
-
exit if
|
14
|
+
exit if Window.instance&.exit_on_opengl_error?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def preload_default_shaders
|
19
|
+
shaders = %w[g_buffer lighting]
|
20
|
+
shaders.each do |shader|
|
21
|
+
Shader.new(
|
22
|
+
name: shader,
|
23
|
+
includes_dir: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/include",
|
24
|
+
vertex: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/vertex/#{shader}.glsl",
|
25
|
+
fragment: "#{CYBERARM_ENGINE_ROOT_PATH}/assets/shaders/fragment/#{shader}.glsl"
|
26
|
+
)
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
@@ -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
|
@@ -62,11 +62,11 @@ module CyberarmEngine
|
|
62
62
|
|
63
63
|
def update
|
64
64
|
# TOP
|
65
|
-
@top.x = @element.x
|
65
|
+
@top.x = @element.x + @element.style.border_thickness_left
|
66
66
|
@top.y = @element.y
|
67
67
|
@top.z = @element.z
|
68
68
|
|
69
|
-
@top.width = @element.width
|
69
|
+
@top.width = @element.width - @element.style.border_thickness_left
|
70
70
|
@top.height = @element.style.border_thickness_top
|
71
71
|
|
72
72
|
# RIGHT
|