retrograph_easy 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +19 -0
- data/README +13 -0
- data/Rakefile +64 -0
- data/demos/defense.rb +413 -0
- data/demos/logo.rb +34 -0
- data/lib/retrograph/easy/app.rb +257 -0
- data/lib/retrograph/easy/constants.rb +35 -0
- data/lib/retrograph/easy/controllers.rb +184 -0
- data/lib/retrograph/easy/display.rb +173 -0
- data/lib/retrograph/easy/logo.rb +287 -0
- data/lib/retrograph/easy/periodic.rb +99 -0
- data/lib/retrograph/easy/sprites.rb +133 -0
- data/lib/retrograph/easy.rb +32 -0
- data/lib/retrograph/sdl.rb +26 -0
- data/lib/retrograph.rb +29 -0
- data/spec/easy_spec.rb +6 -0
- metadata +83 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
# retrograph/easy/app
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
require 'sdl'
|
25
|
+
require 'retrograph/easy/display'
|
26
|
+
require 'retrograph/easy/periodic'
|
27
|
+
require 'retrograph/easy/sprites'
|
28
|
+
require 'retrograph/easy/controllers'
|
29
|
+
|
30
|
+
module Retrograph
|
31
|
+
module Easy
|
32
|
+
|
33
|
+
class Quit < Exception
|
34
|
+
def initialize(message="User quit")
|
35
|
+
super(message)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class App
|
40
|
+
def initialize(display)
|
41
|
+
@_retrograph_held_event = nil
|
42
|
+
@_retrograph_display = display
|
43
|
+
@_retrograph_sprite_manager = SpriteManager.new(display)
|
44
|
+
@_retrograph_controller_manager = ControllerManager.new
|
45
|
+
@_retrograph_controllers =
|
46
|
+
@_retrograph_controller_manager.controllers.freeze
|
47
|
+
@_retrograph_periodic_manager = PeriodicManager.new
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :_retrograph_controllers
|
51
|
+
alias_method :controllers, :_retrograph_controllers
|
52
|
+
remove_method :_retrograph_controllers
|
53
|
+
|
54
|
+
def title(new_title)
|
55
|
+
@_retrograph_display.title = new_title
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def start(label, interval, phases=1)
|
60
|
+
@_retrograph_periodic_manager.start label, interval, phases
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def stop(label)
|
65
|
+
@_retrograph_periodic_manager.stop label
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def frame_for?(label)
|
70
|
+
@_retrograph_periodic_manager.frame_for? label
|
71
|
+
end
|
72
|
+
|
73
|
+
def phase_of(label)
|
74
|
+
@_retrograph_periodic_manager.phase_of label
|
75
|
+
end
|
76
|
+
|
77
|
+
def already?(label)
|
78
|
+
@_retrograph_periodic_manager.already? label
|
79
|
+
end
|
80
|
+
|
81
|
+
def clear_sprites
|
82
|
+
@_retrograph_sprite_manager.clear_sprites
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def sprite(x, y, pattern, flags)
|
87
|
+
@_retrograph_sprite_manager.add_sprite(x, y, pattern, flags)
|
88
|
+
end
|
89
|
+
|
90
|
+
def multi_sprite(x, y, pattern, width_tiles, height_tiles, flags)
|
91
|
+
@_retrograph_sprite_manager.add_multi_sprite(x, y, pattern, width_tiles, height_tiles, flags)
|
92
|
+
end
|
93
|
+
|
94
|
+
def sprite_group(x, y, width, height, flags)
|
95
|
+
@_retrograph_sprite_manager.add_sprite_group(x, y, width, height, flags) do
|
96
|
+
yield
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def palette_entry_rgb(index, r, g, b)
|
101
|
+
r = (r * 255).round if Float === r
|
102
|
+
g = (g * 255).round if Float === g
|
103
|
+
b = (b * 255).round if Float === b
|
104
|
+
raise RangeError, "index out of range" if index < 0 or index > 31
|
105
|
+
entry = ((r >> 2) & 0x30) |
|
106
|
+
((g >> 4) & 0x0c) |
|
107
|
+
((b >> 6) & 0x03)
|
108
|
+
palette_entry(index, entry)
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def palette_entry(index, entry)
|
113
|
+
@_retrograph_display.write_vdu_byte(0x7f00+index, entry)
|
114
|
+
end
|
115
|
+
|
116
|
+
def reset_vdu
|
117
|
+
write_vdu(0x0000, "\000" * 0x4000)
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
def vdu_mode(mode)
|
122
|
+
write_vdu_byte(0x7ff8, mode)
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def write_vdu(offset, data)
|
127
|
+
@_retrograph_display.write_vdu(offset, data)
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def write_vdu_byte(offset, byte)
|
132
|
+
@_retrograph_display.write_vdu_byte(offset, byte)
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
136
|
+
def tile_pattern_1bit(base, index, data)
|
137
|
+
@_retrograph_display.write_vdu(base + index * 8, data)
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
def tile_pattern_2bit(base, index, data)
|
142
|
+
@_retrograph_display.write_vdu(base + index * 16, data)
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def tile_pattern_4bit(base, index, data)
|
147
|
+
@_retrograph_display.write_vdu(base + index * 32, data)
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def sprite_pattern(base, index, data)
|
152
|
+
tile_pattern_4bit(base + 0x2000, index, data)
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
def wait_scanlines(count)
|
157
|
+
@_retrograph_display.wait_scanlines(count)
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
def quit
|
162
|
+
raise Quit
|
163
|
+
end
|
164
|
+
|
165
|
+
def _suspend
|
166
|
+
while event = SDL::Event2.wait
|
167
|
+
case event
|
168
|
+
when SDL::Event2::Quit
|
169
|
+
quit
|
170
|
+
when SDL::Event2::Active
|
171
|
+
if event.gain and event.state == 2
|
172
|
+
break
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
while event = SDL::Event2.wait
|
177
|
+
case event
|
178
|
+
when SDL::Event2::Quit
|
179
|
+
quit
|
180
|
+
when SDL::Event2::KeyDown
|
181
|
+
case event.sym
|
182
|
+
when SDL::Key::RALT, SDL::Key::LALT
|
183
|
+
# ignore alt presses
|
184
|
+
else
|
185
|
+
@_retrograph_held_event = event
|
186
|
+
break
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
private :_suspend
|
192
|
+
|
193
|
+
def each_of_n_frames(n_frames)
|
194
|
+
each_frame(n_frames) { yield }
|
195
|
+
end
|
196
|
+
|
197
|
+
def each_frame(n_frames=nil)
|
198
|
+
count = 0
|
199
|
+
@_retrograph_display.each_frame do
|
200
|
+
break if n_frames == count
|
201
|
+
while event = (@_retrograph_held_event || SDL::Event2.poll)
|
202
|
+
@_retrograph_held_event = nil
|
203
|
+
case event
|
204
|
+
when SDL::Event2::Quit
|
205
|
+
quit
|
206
|
+
when SDL::Event2::Active
|
207
|
+
if not event.gain and event.state == 2
|
208
|
+
_suspend
|
209
|
+
next
|
210
|
+
end
|
211
|
+
when SDL::Event2::KeyDown
|
212
|
+
@_retrograph_controller_manager.key_pressed(event.sym)
|
213
|
+
if (event.mod & SDL::Key::MOD_ALT).nonzero?
|
214
|
+
case event.sym
|
215
|
+
when SDL::Key::RETURN
|
216
|
+
@_retrograph_display.toggle_fullscreen
|
217
|
+
when SDL::Key::F4
|
218
|
+
quit
|
219
|
+
when SDL::Key::TAB
|
220
|
+
if @_retrograph_display.managed and @_retrograph_display.fullscreen
|
221
|
+
@_retrograph_display.minimize
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
case event.sym
|
226
|
+
when SDL::Key::ESCAPE
|
227
|
+
quit
|
228
|
+
when SDL::Key::F11
|
229
|
+
@_retrograph_display.toggle_fullscreen
|
230
|
+
end
|
231
|
+
when SDL::Event2::KeyUp
|
232
|
+
@_retrograph_controller_manager.key_released(event.sym)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
yield
|
236
|
+
@_retrograph_periodic_manager.tick()
|
237
|
+
count += 1 if n_frames
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
@display = Display.new
|
243
|
+
|
244
|
+
class << self
|
245
|
+
def app(&block)
|
246
|
+
begin
|
247
|
+
@display.open do
|
248
|
+
app = App.new(@display)
|
249
|
+
app.instance_eval &block
|
250
|
+
end
|
251
|
+
rescue Quit
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# retrograph/easy/constants
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
module Retrograph
|
25
|
+
module Easy
|
26
|
+
|
27
|
+
TEXT_MODE_A = 0
|
28
|
+
TEXT_MODE_B = 1
|
29
|
+
GRAPHICS_MODE_A = 2
|
30
|
+
GRAPHICS_MODE_B = 3
|
31
|
+
ENABLE_SPRITES = 1 << 3
|
32
|
+
ENABLE_BG = 1 << 2
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# retrograph/easy/controllers
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
module Retrograph
|
25
|
+
module Easy
|
26
|
+
|
27
|
+
class Rocker
|
28
|
+
attr_reader :state
|
29
|
+
|
30
|
+
def initialize(minus_state, neutral_state, plus_state)
|
31
|
+
@minus_state = minus_state
|
32
|
+
@neutral_state = neutral_state
|
33
|
+
@plus_state = plus_state
|
34
|
+
@state = @neutral_state
|
35
|
+
@both_pressed = false
|
36
|
+
end
|
37
|
+
|
38
|
+
def plus_pressed
|
39
|
+
@both_pressed = true if @state != @neutral_state
|
40
|
+
@state = @plus_state
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def minus_pressed
|
45
|
+
@both_pressed = true if @state != @neutral_state
|
46
|
+
@state = @minus_state
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def plus_released
|
51
|
+
if @both_pressed
|
52
|
+
@both_pressed = false
|
53
|
+
@state = @minus_state
|
54
|
+
else
|
55
|
+
@state = @neutral_state
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def minus_released
|
61
|
+
if @both_pressed
|
62
|
+
@both_pressed = false
|
63
|
+
@state = @plus_state
|
64
|
+
else
|
65
|
+
@state = @neutral_state
|
66
|
+
end
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
button_names = %w(up down left right a b select start)
|
72
|
+
controller_fields = button_names.map { |n| "#{n}_pressed".intern } +
|
73
|
+
[:horizontal, :vertical]
|
74
|
+
|
75
|
+
Controller = Struct.new *controller_fields
|
76
|
+
Controller.class_eval do
|
77
|
+
FIELD_DEFAULTS = button_names.map { false } + [0, 0]
|
78
|
+
|
79
|
+
def initialize
|
80
|
+
super(*FIELD_DEFAULTS)
|
81
|
+
end
|
82
|
+
|
83
|
+
for name in button_names
|
84
|
+
field = "#{name}_pressed".intern
|
85
|
+
alias_method "#{field}?".intern, field
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ControllerManager
|
90
|
+
KEYMAP = {
|
91
|
+
SDL::Key::UP => :up,
|
92
|
+
SDL::Key::DOWN => :down,
|
93
|
+
SDL::Key::LEFT => :left,
|
94
|
+
SDL::Key::RIGHT => :right,
|
95
|
+
SDL::Key::LCTRL => :a,
|
96
|
+
SDL::Key::RCTRL => :a,
|
97
|
+
SDL::Key::SPACE => :b,
|
98
|
+
SDL::Key::LSHIFT => :select,
|
99
|
+
SDL::Key::RSHIFT => :select,
|
100
|
+
SDL::Key::TAB => :select,
|
101
|
+
SDL::Key::RETURN => :start,
|
102
|
+
SDL::Key::W => :up,
|
103
|
+
SDL::Key::S => :down,
|
104
|
+
SDL::Key::D => :right,
|
105
|
+
SDL::Key::A => :left,
|
106
|
+
SDL::Key::Z => :select,
|
107
|
+
SDL::Key::X => :b,
|
108
|
+
SDL::Key::C => :a,
|
109
|
+
SDL::Key::COMMA => :a,
|
110
|
+
SDL::Key::PERIOD => :b,
|
111
|
+
SDL::Key::SLASH => :select
|
112
|
+
}
|
113
|
+
|
114
|
+
def initialize
|
115
|
+
@controllers = (0...2).map { Controller.new }
|
116
|
+
@horizontal = @controllers.map { Rocker.new(-1, 0, 1) }
|
117
|
+
@vertical = @controllers.map { Rocker.new(-1, 0, 1) }
|
118
|
+
end
|
119
|
+
|
120
|
+
def controllers
|
121
|
+
@controllers.dup
|
122
|
+
end
|
123
|
+
|
124
|
+
def key_pressed(key)
|
125
|
+
case KEYMAP[key]
|
126
|
+
when :up
|
127
|
+
@controllers[0].up_pressed = true
|
128
|
+
@vertical[0].minus_pressed
|
129
|
+
@controllers[0].vertical = @vertical[0].state
|
130
|
+
when :down
|
131
|
+
@controllers[0].down_pressed = true
|
132
|
+
@vertical[0].plus_pressed
|
133
|
+
@controllers[0].vertical = @vertical[0].state
|
134
|
+
when :left
|
135
|
+
@controllers[0].left_pressed = true
|
136
|
+
@horizontal[0].minus_pressed
|
137
|
+
@controllers[0].horizontal = @horizontal[0].state
|
138
|
+
when :right
|
139
|
+
@controllers[0].right_pressed = true
|
140
|
+
@horizontal[0].plus_pressed
|
141
|
+
@controllers[0].horizontal = @horizontal[0].state
|
142
|
+
when :a
|
143
|
+
@controllers[0].a_pressed = true
|
144
|
+
when :b
|
145
|
+
@controllers[0].b_pressed = true
|
146
|
+
when :select
|
147
|
+
@controllers[0].select_pressed = true
|
148
|
+
when :start
|
149
|
+
@controllers[0].start_pressed = true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def key_released(key)
|
154
|
+
case KEYMAP[key]
|
155
|
+
when :up
|
156
|
+
@controllers[0].up_pressed = false
|
157
|
+
@vertical[0].minus_pressed
|
158
|
+
@controllers[0].vertical = @vertical[0].state
|
159
|
+
when :down
|
160
|
+
@controllers[0].down_pressed = false
|
161
|
+
@vertical[0].plus_released
|
162
|
+
@controllers[0].vertical = @vertical[0].state
|
163
|
+
when :left
|
164
|
+
@controllers[0].left_pressed = false
|
165
|
+
@horizontal[0].minus_released
|
166
|
+
@controllers[0].horizontal = @horizontal[0].state
|
167
|
+
when :right
|
168
|
+
@controllers[0].right_pressed = false
|
169
|
+
@horizontal[0].plus_released
|
170
|
+
@controllers[0].horizontal = @horizontal[0].state
|
171
|
+
when :a
|
172
|
+
@controllers[0].a_pressed = false
|
173
|
+
when :b
|
174
|
+
@controllers[0].b_pressed = false
|
175
|
+
when :select
|
176
|
+
@controllers[0].select_pressed = false
|
177
|
+
when :start
|
178
|
+
@controllers[0].start_pressed = false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# retrograph/easy/display
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
require 'retrograph/sdl'
|
25
|
+
|
26
|
+
module Retrograph
|
27
|
+
module Easy
|
28
|
+
|
29
|
+
FRAMES_PER_SECOND = 25
|
30
|
+
FRAME_TIME_MS = 1000/FRAMES_PER_SECOND
|
31
|
+
|
32
|
+
class Display
|
33
|
+
BEZEL_THICKNESS = 16
|
34
|
+
|
35
|
+
def initialize(sdl=SDL, vdu_class=VDU)
|
36
|
+
@sdl = sdl
|
37
|
+
@vdu = nil
|
38
|
+
@vdu_class = vdu_class
|
39
|
+
@surface = nil
|
40
|
+
@managed = false
|
41
|
+
@fullscreen = false
|
42
|
+
@old_fullscreen = false
|
43
|
+
@screen = nil
|
44
|
+
@bezel_image = nil
|
45
|
+
@title = "Retrograph application"
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :title
|
49
|
+
attr_reader :fullscreen
|
50
|
+
attr_reader :managed
|
51
|
+
|
52
|
+
def title=(value)
|
53
|
+
@title = value.to_s
|
54
|
+
@sdl::WM.set_caption(@title, @title)
|
55
|
+
value
|
56
|
+
end
|
57
|
+
|
58
|
+
def fullscreen=(value)
|
59
|
+
@fullscreen = !!value
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def toggle_fullscreen
|
64
|
+
@fullscreen = !@fullscreen
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_vdu(offset, data)
|
69
|
+
@vdu.write(offset, data)
|
70
|
+
end
|
71
|
+
|
72
|
+
def write_vdu_byte(offset, byte)
|
73
|
+
@vdu.write_byte(offset, byte)
|
74
|
+
end
|
75
|
+
|
76
|
+
def wait_scanlines(count)
|
77
|
+
@vdu.wait_scanlines(count)
|
78
|
+
end
|
79
|
+
|
80
|
+
def each_frame
|
81
|
+
while true
|
82
|
+
start_time = @sdl.get_ticks
|
83
|
+
@surface = @vdu.render_frame_sdl { yield }
|
84
|
+
_set_mode if @managed and @old_fullscreen != @fullscreen
|
85
|
+
@old_fullscreen = @fullscreen
|
86
|
+
_update_screen
|
87
|
+
end_time = @sdl.get_ticks
|
88
|
+
sleep_time = FRAME_TIME_MS - (end_time - start_time)
|
89
|
+
sleep(sleep_time / 1000.0) if sleep_time > 0
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def open
|
94
|
+
@sdl.init SDL::INIT_VIDEO
|
95
|
+
info = @sdl::Screen.info
|
96
|
+
@managed = info.wm_available
|
97
|
+
@vdu = @vdu_class.new
|
98
|
+
@surface = @vdu.render_frame_sdl
|
99
|
+
_set_mode
|
100
|
+
if block_given?
|
101
|
+
begin
|
102
|
+
yield
|
103
|
+
ensure
|
104
|
+
close
|
105
|
+
end
|
106
|
+
else
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def minimize
|
112
|
+
@sdl::WM.iconify
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def close
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
def _bezel_func(d)
|
121
|
+
((1.0-(d-0.5)*2))**2 + 0.07
|
122
|
+
end
|
123
|
+
private :_bezel_func
|
124
|
+
|
125
|
+
def _generate_bezel
|
126
|
+
bezel_color = @bezel_image.format.map_rgb(8, 8, 8)
|
127
|
+
clear_color = @bezel_image.format.map_rgb(255, 255, 255)
|
128
|
+
@bezel_image.fill_rect(0, 0, OUTPUT_WIDTH, OUTPUT_HEIGHT, clear_color)
|
129
|
+
for i in 0...BEZEL_THICKNESS
|
130
|
+
section = _bezel_func(i.to_f / (BEZEL_THICKNESS-1))
|
131
|
+
section = 1.0 if section > 1.0
|
132
|
+
hlength = (OUTPUT_WIDTH / 2 * section).to_i
|
133
|
+
vlength = (OUTPUT_HEIGHT / 2 * section).to_i
|
134
|
+
@bezel_image.fill_rect(0, i, hlength, 1, bezel_color)
|
135
|
+
@bezel_image.fill_rect(0, OUTPUT_HEIGHT - 1 - i, hlength, 1, bezel_color)
|
136
|
+
@bezel_image.fill_rect(OUTPUT_WIDTH - hlength, i, hlength, 1, bezel_color)
|
137
|
+
@bezel_image.fill_rect(OUTPUT_WIDTH - hlength, OUTPUT_HEIGHT - 1 - i, hlength, 1, bezel_color)
|
138
|
+
@bezel_image.fill_rect(i, 0, 1, vlength, bezel_color)
|
139
|
+
@bezel_image.fill_rect(OUTPUT_WIDTH - 1 - i, 0, 1, vlength, bezel_color)
|
140
|
+
@bezel_image.fill_rect(i, OUTPUT_HEIGHT - vlength, 1, vlength, bezel_color)
|
141
|
+
@bezel_image.fill_rect(OUTPUT_WIDTH - 1 - i, OUTPUT_HEIGHT - vlength, 1, vlength, bezel_color)
|
142
|
+
end
|
143
|
+
@bezel_image.set_color_key(SDL::SRCCOLORKEY | SDL::RLEACCEL, clear_color)
|
144
|
+
end
|
145
|
+
private :_generate_bezel
|
146
|
+
|
147
|
+
def _set_mode
|
148
|
+
flags = SDL::HWSURFACE | SDL::DOUBLEBUF
|
149
|
+
flags |= SDL::FULLSCREEN if fullscreen?
|
150
|
+
@screen = @sdl::Screen.open(OUTPUT_WIDTH, OUTPUT_HEIGHT, 32, flags)
|
151
|
+
@bezel_image = @sdl::Surface.new(0, OUTPUT_WIDTH, OUTPUT_HEIGHT,
|
152
|
+
@screen.format)
|
153
|
+
_generate_bezel
|
154
|
+
@sdl::WM.set_caption(@title, @title)
|
155
|
+
@sdl::Mouse.hide
|
156
|
+
_update_screen
|
157
|
+
end
|
158
|
+
private :_set_mode
|
159
|
+
|
160
|
+
def _update_screen
|
161
|
+
@sdl::Surface.blit(@surface, 0, 0, 0, 0, @screen, 0, 0)
|
162
|
+
@sdl::Surface.blit(@bezel_image, 0, 0, 0, 0, @screen, 0, 0)
|
163
|
+
@screen.flip
|
164
|
+
end
|
165
|
+
private :_update_screen
|
166
|
+
|
167
|
+
def fullscreen?
|
168
|
+
not @managed or @fullscreen
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|