teek 0.1.2 → 0.1.4

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/Rakefile +121 -22
  4. data/ext/teek/extconf.rb +19 -1
  5. data/ext/teek/tcltkbridge.c +44 -2
  6. data/ext/teek/tcltkbridge.h +3 -0
  7. data/ext/teek/tkdrop.c +66 -0
  8. data/ext/teek/tkdrop.h +26 -0
  9. data/ext/teek/tkdrop_macos.m +141 -0
  10. data/ext/teek/tkdrop_win.c +232 -0
  11. data/ext/teek/tkdrop_x11.c +337 -0
  12. data/ext/teek/tkwin.c +42 -0
  13. data/lib/teek/platform.rb +29 -0
  14. data/lib/teek/version.rb +1 -1
  15. data/lib/teek.rb +248 -7
  16. data/teek.gemspec +3 -2
  17. metadata +7 -45
  18. data/sample/calculator.rb +0 -255
  19. data/sample/debug_demo.rb +0 -43
  20. data/sample/goldberg.rb +0 -1803
  21. data/sample/goldberg_helpers.rb +0 -170
  22. data/sample/minesweeper/assets/MINESWEEPER_0.png +0 -0
  23. data/sample/minesweeper/assets/MINESWEEPER_1.png +0 -0
  24. data/sample/minesweeper/assets/MINESWEEPER_2.png +0 -0
  25. data/sample/minesweeper/assets/MINESWEEPER_3.png +0 -0
  26. data/sample/minesweeper/assets/MINESWEEPER_4.png +0 -0
  27. data/sample/minesweeper/assets/MINESWEEPER_5.png +0 -0
  28. data/sample/minesweeper/assets/MINESWEEPER_6.png +0 -0
  29. data/sample/minesweeper/assets/MINESWEEPER_7.png +0 -0
  30. data/sample/minesweeper/assets/MINESWEEPER_8.png +0 -0
  31. data/sample/minesweeper/assets/MINESWEEPER_F.png +0 -0
  32. data/sample/minesweeper/assets/MINESWEEPER_M.png +0 -0
  33. data/sample/minesweeper/assets/MINESWEEPER_X.png +0 -0
  34. data/sample/minesweeper/minesweeper.rb +0 -452
  35. data/sample/optcarrot/vendor/optcarrot/apu.rb +0 -856
  36. data/sample/optcarrot/vendor/optcarrot/config.rb +0 -257
  37. data/sample/optcarrot/vendor/optcarrot/cpu.rb +0 -1162
  38. data/sample/optcarrot/vendor/optcarrot/driver.rb +0 -144
  39. data/sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb +0 -14
  40. data/sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb +0 -105
  41. data/sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb +0 -153
  42. data/sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb +0 -14
  43. data/sample/optcarrot/vendor/optcarrot/nes.rb +0 -105
  44. data/sample/optcarrot/vendor/optcarrot/opt.rb +0 -168
  45. data/sample/optcarrot/vendor/optcarrot/pad.rb +0 -92
  46. data/sample/optcarrot/vendor/optcarrot/palette.rb +0 -65
  47. data/sample/optcarrot/vendor/optcarrot/ppu.rb +0 -1468
  48. data/sample/optcarrot/vendor/optcarrot/rom.rb +0 -143
  49. data/sample/optcarrot/vendor/optcarrot.rb +0 -14
  50. data/sample/optcarrot.rb +0 -354
  51. data/sample/paint/assets/bucket.png +0 -0
  52. data/sample/paint/assets/cursor.png +0 -0
  53. data/sample/paint/assets/eraser.png +0 -0
  54. data/sample/paint/assets/pencil.png +0 -0
  55. data/sample/paint/assets/spray.png +0 -0
  56. data/sample/paint/layer.rb +0 -255
  57. data/sample/paint/layer_manager.rb +0 -179
  58. data/sample/paint/paint_demo.rb +0 -837
  59. data/sample/paint/sparse_pixel_buffer.rb +0 -202
  60. data/sample/sdl2_demo.rb +0 -318
  61. data/sample/threading_demo.rb +0 -494
@@ -1,143 +0,0 @@
1
- module Optcarrot
2
- # Cartridge class (with NROM mapper implemented)
3
- class ROM
4
- MAPPER_DB = { 0x00 => self }
5
-
6
- # These are optional
7
- require_relative "mapper/mmc1"
8
- require_relative "mapper/uxrom"
9
- require_relative "mapper/cnrom"
10
- require_relative "mapper/mmc3"
11
-
12
- def self.zip_extract(filename)
13
- require "zlib"
14
- bin = File.binread(filename)
15
- loop do
16
- sig, _, flags, comp, _, _, _, data_len, _, fn_len, ext_len = bin.slice!(0, 30).unpack("a4v5V3v2")
17
- break if sig != "PK\3\4".b
18
- fn = bin.slice!(0, fn_len)
19
- bin.slice!(0, ext_len)
20
- data = bin.slice!(0, data_len)
21
- next if File.extname(fn).downcase != ".nes"
22
- next if flags & 0x11 != 0
23
- next if comp != 0 && comp != 8
24
- if comp == 8
25
- zs = Zlib::Inflate.new(-15)
26
- data = zs.inflate(data)
27
- zs.finish
28
- zs.close
29
- end
30
- return data
31
- end
32
- raise "failed to extract ROM file from `#{ filename }'"
33
- end
34
-
35
- def self.load(conf, cpu, ppu)
36
- filename = conf.romfile
37
- basename = File.basename(filename)
38
-
39
- blob = (File.extname(filename) == ".zip" ? zip_extract(filename) : File.binread(filename)).bytes
40
-
41
- # parse mapper
42
- mapper = (blob[6] >> 4) | (blob[7] & 0xf0)
43
-
44
- klass = MAPPER_DB[mapper]
45
- raise NotImplementedError, "Unsupported mapper type 0x%02x" % mapper unless klass
46
- klass.new(conf, cpu, ppu, basename, blob)
47
- end
48
-
49
- class InvalidROM < StandardError
50
- end
51
-
52
- def parse_header(buf)
53
- raise InvalidROM, "Missing 16-byte header" if buf.size < 16
54
- raise InvalidROM, "Missing 'NES' constant in header" if buf[0, 4] != "NES\x1a".bytes
55
- raise NotImplementedError, "trainer not supported" if buf[6][2] == 1
56
- raise NotImplementedError, "VS cart not supported" if buf[7][0] == 1
57
- raise NotImplementedError, "PAL not supported" unless buf[9][0] == 0
58
-
59
- prg_banks = buf[4]
60
- chr_banks = buf[5]
61
- @mirroring = buf[6][0] == 0 ? :horizontal : :vertical
62
- @mirroring = :four_screen if buf[6][3] == 1
63
- @battery = buf[6][1] == 1
64
- @mapper = (buf[6] >> 4) | (buf[7] & 0xf0)
65
- ram_banks = [1, buf[8]].max
66
-
67
- return prg_banks, chr_banks, ram_banks
68
- end
69
-
70
- def initialize(conf, cpu, ppu, basename, buf)
71
- @conf = conf
72
- @cpu = cpu
73
- @ppu = ppu
74
- @basename = basename
75
-
76
- prg_count, chr_count, wrk_count = parse_header(buf.slice!(0, 16))
77
-
78
- raise InvalidROM, "EOF in ROM bank data" if buf.size < 0x4000 * prg_count
79
- @prg_banks = (0...prg_count).map { buf.slice!(0, 0x4000) }
80
-
81
- raise InvalidROM, "EOF in CHR bank data" if buf.size < 0x2000 * chr_count
82
- @chr_banks = (0...chr_count).map { buf.slice!(0, 0x2000) }
83
-
84
- @prg_ref = [nil] * 0x10000
85
- @prg_ref[0x8000, 0x4000] = @prg_banks.first
86
- @prg_ref[0xc000, 0x4000] = @prg_banks.last
87
-
88
- @chr_ram = chr_count == 0 # No CHR bank implies CHR-RAM (writable CHR bank)
89
- @chr_ref = @chr_ram ? [0] * 0x2000 : @chr_banks[0].dup
90
-
91
- @wrk_readable = wrk_count > 0
92
- @wrk_writable = false
93
- @wrk = wrk_count > 0 ? (0x6000..0x7fff).map {|addr| addr >> 8 } : nil
94
-
95
- init
96
-
97
- @ppu.nametables = @mirroring
98
- @ppu.set_chr_mem(@chr_ref, @chr_ram)
99
- end
100
-
101
- def init
102
- end
103
-
104
- def reset
105
- @cpu.add_mappings(0x8000..0xffff, @prg_ref, nil)
106
- end
107
-
108
- def inspect
109
- [
110
- "Mapper: #{ @mapper } (#{ self.class.to_s.split("::").last })",
111
- "PRG Banks: #{ @prg_banks.size }",
112
- "CHR Banks: #{ @chr_banks.size }",
113
- "Mirroring: #{ @mirroring }",
114
- ].join("\n")
115
- end
116
-
117
- def peek_6000(addr)
118
- @wrk_readable ? @wrk[addr - 0x6000] : (addr >> 8)
119
- end
120
-
121
- def poke_6000(addr, data)
122
- @wrk[addr - 0x6000] = data if @wrk_writable
123
- end
124
-
125
- def vsync
126
- end
127
-
128
- def load_battery
129
- return unless @battery
130
- sav = @basename + ".sav"
131
- return unless File.readable?(sav)
132
- sav = File.binread(sav)
133
- @wrk.replace(sav.bytes)
134
- end
135
-
136
- def save_battery
137
- return unless @battery
138
- sav = @basename + ".sav"
139
- puts "Saving: " + sav
140
- File.binwrite(sav, @wrk.pack("C*"))
141
- end
142
- end
143
- end
@@ -1,14 +0,0 @@
1
- # Optcarrot namespace
2
- module Optcarrot
3
- VERSION = "0.9.0"
4
- end
5
-
6
- require_relative "optcarrot/nes"
7
- require_relative "optcarrot/rom"
8
- require_relative "optcarrot/pad"
9
- require_relative "optcarrot/cpu"
10
- require_relative "optcarrot/apu"
11
- require_relative "optcarrot/ppu"
12
- require_relative "optcarrot/palette"
13
- require_relative "optcarrot/driver"
14
- require_relative "optcarrot/config"
data/sample/optcarrot.rb DELETED
@@ -1,354 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
- # teek-record: title=Optcarrot NES (Thwaite)
4
-
5
- # Optcarrot NES Emulator running on teek-sdl2
6
- #
7
- # Uses teek for the window and teek-sdl2 for GPU-accelerated rendering.
8
- # Optcarrot is installed automatically via bundler/inline.
9
- #
10
- # Usage:
11
- # ruby -Ilib -Iteek-sdl2/lib sample/optcarrot.rb path/to/rom.nes
12
- #
13
- # Controls:
14
- # Arrow keys - D-pad
15
- # Z - A button
16
- # X - B button
17
- # Return - Start
18
- # Space - Select
19
- # Q / Escape - Quit
20
-
21
- FALLBACK_ROMS = [
22
- File.join(__dir__, 'optcarrot', 'thwaite.nes'),
23
- ].freeze
24
-
25
- rom_path = ARGV.find { |a| !a.start_with?('--') }
26
- unless rom_path
27
- rom_path = FALLBACK_ROMS.find { |p| File.exist?(p) }
28
- unless rom_path
29
- abort <<~USAGE
30
- Usage: ruby sample/optcarrot.rb [options] <rom.nes>
31
-
32
- Options are passed through to optcarrot.
33
- ROM file must be provided — it is not bundled.
34
- Fallback locations checked:
35
- #{FALLBACK_ROMS.join("\n ")}
36
- USAGE
37
- end
38
- end
39
-
40
- unless File.exist?(rom_path)
41
- abort "ROM not found: #{rom_path}"
42
- end
43
-
44
- $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
45
- $LOAD_PATH.unshift File.expand_path('../teek-sdl2/lib', __dir__)
46
- $LOAD_PATH.unshift File.join(__dir__, 'optcarrot', 'vendor')
47
- require 'teek'
48
- require 'teek/sdl2'
49
- require 'optcarrot'
50
-
51
- # --- Video Driver -----------------------------------------------------------
52
-
53
- class TeekVideo < Optcarrot::Video
54
- NES_WIDTH = 256
55
- NES_HEIGHT = 224
56
-
57
- def init
58
- super
59
-
60
- @app = Teek::App.new
61
- @app.show
62
- @app.set_window_title('Optcarrot NES — teek-sdl2')
63
- @app.set_window_geometry("#{NES_WIDTH * 2}x#{NES_HEIGHT * 2}")
64
- @app.update
65
-
66
- @viewport = Teek::SDL2::Viewport.new(@app, width: NES_WIDTH * 2, height: NES_HEIGHT * 2)
67
- @viewport.pack(fill: :both, expand: true)
68
-
69
- @texture = @viewport.renderer.create_texture(NES_WIDTH, NES_HEIGHT, :streaming)
70
-
71
- # Build palette: optcarrot palette_rgb is [[r,g,b], ...] → ARGB8888
72
- @palette = @palette_rgb.map do |r, g, b|
73
- 0xFF000000 | (r << 16) | (g << 8) | b
74
- end
75
-
76
- # Load font for status overlay
77
- font_path = File.join(__dir__, '..', 'teek-sdl2', 'assets', 'JetBrainsMonoNL-Regular.ttf')
78
- @status_font = @viewport.renderer.load_font(font_path, 13)
79
-
80
- # Auto-focus viewport for keyboard input
81
- @app.tcl_eval("focus -force #{@viewport.frame.path}")
82
- @app.update
83
-
84
- # FPS tracking
85
- @fps_count = 0
86
- @fps_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
87
- @frame_num = 0
88
- @fps_text = '0.0 fps'
89
- end
90
-
91
- def tick(colors)
92
- return super if @disposed
93
-
94
- # colors is already palette-mapped uint32 ARGB values from the PPU.
95
- # Pack to byte string for texture update.
96
- @texture.update(Teek::SDL2::Pixels.pack_uint32(colors, NES_WIDTH, NES_HEIGHT))
97
-
98
- @viewport.render do |r|
99
- r.clear(0, 0, 0)
100
- r.copy(@texture)
101
-
102
- # Status overlay at bottom of game surface (outline + green text)
103
- right_text = "Hello from Teek! Ruby #{RUBY_VERSION}"
104
- lx, ly = 6, NES_HEIGHT * 2 - 18
105
- rw, = @status_font.measure(right_text)
106
- rx, ry = NES_WIDTH * 2 - rw - 6, NES_HEIGHT * 2 - 18
107
- # Black outline (draw offset in 4 directions)
108
- [[-1,0],[1,0],[0,-1],[0,1]].each do |dx, dy|
109
- r.draw_text(lx+dx, ly+dy, @fps_text, font: @status_font, r: 0, g: 0, b: 0)
110
- r.draw_text(rx+dx, ry+dy, right_text, font: @status_font, r: 0, g: 0, b: 0)
111
- end
112
- r.draw_text(lx, ly, @fps_text, font: @status_font, r: 0, g: 255, b: 0)
113
- r.draw_text(rx, ry, right_text, font: @status_font, r: 0, g: 255, b: 0)
114
- end
115
-
116
- # FPS display
117
- @fps_count += 1
118
- @frame_num += 1
119
- now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
120
- elapsed = now - @fps_time
121
- if elapsed >= 1.0
122
- fps = @fps_count / elapsed
123
- @fps_text = "#{fps.round(1)} fps | frame #{@frame_num}"
124
- @app.set_window_title("Optcarrot — #{fps.round(1)} fps")
125
- @fps_count = 0
126
- @fps_time = now
127
- end
128
-
129
- # Process Tk events so window stays responsive
130
- @app.update
131
-
132
- super
133
- end
134
-
135
- def dispose
136
- @disposed = true
137
- @texture&.destroy
138
- @viewport&.destroy
139
- # Don't destroy app here — TeekDemo.finish needs it for the recording
140
- # harness signal. Process exit handles cleanup for interactive mode.
141
- end
142
-
143
- def app
144
- @app
145
- end
146
-
147
- def viewport
148
- @viewport
149
- end
150
- end
151
-
152
- # --- Input Driver ------------------------------------------------------------
153
-
154
- class TeekInput < Optcarrot::Input
155
- KEY_MAP = {
156
- 'left' => :left,
157
- 'right' => :right,
158
- 'up' => :up,
159
- 'down' => :down,
160
- 'z' => :a,
161
- 'x' => :b,
162
- 'return' => :start,
163
- 'space' => :select,
164
- }.freeze
165
-
166
- # Demo script: [{frame:, button:, action: :keydown/:keyup}, ...]
167
- # Thwaite (missile command): title → 1 player → shoot missiles
168
- DEMO_SCRIPT = [
169
- # Title screen — mash Start quickly
170
- { frame: 60, button: :start, action: :keydown },
171
- { frame: 65, button: :start, action: :keyup },
172
- # 1 player select — A
173
- { frame: 80, button: :a, action: :keydown },
174
- { frame: 85, button: :a, action: :keyup },
175
- # Skip any text — A again
176
- { frame: 100, button: :a, action: :keydown },
177
- { frame: 105, button: :a, action: :keyup },
178
- { frame: 120, button: :a, action: :keydown },
179
- { frame: 125, button: :a, action: :keyup },
180
- # Dismiss text screens
181
- { frame: 185, button: :a, action: :keydown },
182
- { frame: 190, button: :a, action: :keyup },
183
- { frame: 230, button: :a, action: :keydown },
184
- { frame: 235, button: :a, action: :keyup },
185
- # Game should be starting — move and shoot aggressively
186
- # Move crosshair right+up, shoot
187
- { frame: 250, button: :right, action: :keydown },
188
- { frame: 250, button: :up, action: :keydown },
189
- { frame: 280, button: :up, action: :keyup },
190
- { frame: 290, button: :right, action: :keyup },
191
- { frame: 295, button: :b, action: :keydown },
192
- { frame: 300, button: :b, action: :keyup },
193
- # Sweep left, shoot
194
- { frame: 320, button: :left, action: :keydown },
195
- { frame: 320, button: :up, action: :keydown },
196
- { frame: 350, button: :up, action: :keyup },
197
- { frame: 380, button: :left, action: :keyup },
198
- { frame: 385, button: :b, action: :keydown },
199
- { frame: 390, button: :b, action: :keyup },
200
- # Sweep right+down, shoot
201
- { frame: 410, button: :right, action: :keydown },
202
- { frame: 410, button: :down, action: :keydown },
203
- { frame: 440, button: :down, action: :keyup },
204
- { frame: 470, button: :right, action: :keyup },
205
- { frame: 475, button: :b, action: :keydown },
206
- { frame: 480, button: :b, action: :keyup },
207
- # Quick left, shoot
208
- { frame: 500, button: :left, action: :keydown },
209
- { frame: 530, button: :left, action: :keyup },
210
- { frame: 535, button: :b, action: :keydown },
211
- { frame: 540, button: :b, action: :keyup },
212
- # Up+right, shoot
213
- { frame: 560, button: :right, action: :keydown },
214
- { frame: 560, button: :up, action: :keydown },
215
- { frame: 590, button: :up, action: :keyup },
216
- { frame: 600, button: :right, action: :keyup },
217
- { frame: 605, button: :b, action: :keydown },
218
- { frame: 610, button: :b, action: :keyup },
219
- # Sweep left, shoot twice
220
- { frame: 630, button: :left, action: :keydown },
221
- { frame: 680, button: :left, action: :keyup },
222
- { frame: 685, button: :b, action: :keydown },
223
- { frame: 690, button: :b, action: :keyup },
224
- { frame: 710, button: :up, action: :keydown },
225
- { frame: 730, button: :up, action: :keyup },
226
- { frame: 735, button: :b, action: :keydown },
227
- { frame: 740, button: :b, action: :keyup },
228
- # Down+right, shoot
229
- { frame: 760, button: :right, action: :keydown },
230
- { frame: 760, button: :down, action: :keydown },
231
- { frame: 790, button: :down, action: :keyup },
232
- { frame: 810, button: :right, action: :keyup },
233
- { frame: 815, button: :b, action: :keydown },
234
- { frame: 820, button: :b, action: :keyup },
235
- # Final flurry — left, shoot, right, shoot
236
- { frame: 840, button: :left, action: :keydown },
237
- { frame: 870, button: :left, action: :keyup },
238
- { frame: 875, button: :b, action: :keydown },
239
- { frame: 880, button: :b, action: :keyup },
240
- { frame: 900, button: :right, action: :keydown },
241
- { frame: 900, button: :up, action: :keydown },
242
- { frame: 925, button: :up, action: :keyup },
243
- { frame: 940, button: :right, action: :keyup },
244
- { frame: 945, button: :b, action: :keydown },
245
- { frame: 950, button: :b, action: :keyup },
246
- ].freeze
247
-
248
- def init
249
- @viewport = @video.viewport
250
- @prev_state = {}
251
- @demo_mode = defined?(TeekDemo) && TeekDemo.active?
252
- @demo_idx = 0
253
- end
254
-
255
- def tick(frame, pads)
256
- # Real keyboard input
257
- KEY_MAP.each do |key, button|
258
- down = @viewport.key_down?(key)
259
- was_down = @prev_state[key]
260
-
261
- if down && !was_down
262
- event(pads, :keydown, button, 0)
263
- elsif !down && was_down
264
- event(pads, :keyup, button, 0)
265
- end
266
-
267
- @prev_state[key] = down
268
- end
269
-
270
- # Demo script — virtual button presses by frame count
271
- if @demo_mode
272
- while @demo_idx < DEMO_SCRIPT.size && DEMO_SCRIPT[@demo_idx][:frame] <= frame
273
- cmd = DEMO_SCRIPT[@demo_idx]
274
- event(pads, cmd[:action], cmd[:button], 0)
275
- @demo_idx += 1
276
- end
277
- end
278
-
279
- # Quit on Q or Escape
280
- if @viewport.key_down?('q') || @viewport.key_down?('escape')
281
- throw :quit_nes
282
- end
283
- end
284
-
285
- def dispose
286
- end
287
- end
288
-
289
- # --- Register drivers and run ------------------------------------------------
290
-
291
- # Inject our drivers into optcarrot's driver database
292
- Optcarrot::Driver::DRIVER_DB[:video][:teek] = :TeekVideo
293
- Optcarrot::Driver::DRIVER_DB[:input][:teek] = :TeekInput
294
- Optcarrot.const_set(:TeekVideo, TeekVideo)
295
- Optcarrot.const_set(:TeekInput, TeekInput)
296
-
297
- # Prevent Driver.load_each from trying to require_relative our inline drivers
298
- original_load_each = Optcarrot::Driver.method(:load_each)
299
- Optcarrot::Driver.define_singleton_method(:load_each) do |conf, type, name|
300
- if name == :teek
301
- klass_name = Optcarrot::Driver::DRIVER_DB[type][name]
302
- return Optcarrot.const_get(klass_name)
303
- end
304
- original_load_each.call(conf, type, name)
305
- end
306
-
307
- # Patch Config's option candidates to accept our driver names
308
- # (candidates are snapshot at class load from DRIVER_DB.keys)
309
- Optcarrot::Config.const_get(:OPTIONS).each do |_section, opts|
310
- opts.each do |_id, opt|
311
- next unless opt[:type] == :driver && opt[:candidates]
312
- opt[:candidates] << :teek unless opt[:candidates].include?(:teek)
313
- end
314
- end
315
-
316
- # Automated demo support (testing and recording)
317
- require_relative '../lib/teek/demo_support'
318
-
319
- # Build argv for optcarrot
320
- optcarrot_argv = ['--video=teek', '--input=teek']
321
-
322
- if TeekDemo.active?
323
- # Run for ~960 frames (~16s) in demo mode
324
- optcarrot_argv << '--frames=960'
325
- end
326
-
327
- ARGV.each { |a| optcarrot_argv << a if a.start_with?('--') }
328
- optcarrot_argv << rom_path
329
-
330
- nes = Optcarrot::NES.new(optcarrot_argv)
331
- video = nes.instance_variable_get(:@video)
332
- TeekDemo.app = video.app
333
-
334
- if TeekDemo.recording?
335
- video.app.set_window_geometry('+0+0')
336
- video.app.tcl_eval('. configure -cursor none')
337
- TeekDemo.signal_recording_ready
338
- end
339
-
340
- catch(:quit_nes) { nes.run }
341
-
342
- if TeekDemo.active?
343
- # Signal recording harness directly (can't use TeekDemo.finish because
344
- # there's no Tk event loop running after the NES exits)
345
- if (port = ENV['TK_STOP_PORT'])
346
- begin
347
- sock = TCPSocket.new('127.0.0.1', port.to_i)
348
- sock.read(1) # wait for harness to stop ffmpeg
349
- sock.close
350
- rescue StandardError
351
- end
352
- end
353
- video.app.destroy('.') rescue nil
354
- end
Binary file
Binary file
Binary file
Binary file
Binary file