teek 0.1.1 → 0.1.2
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/README.md +46 -0
- data/Rakefile +161 -5
- data/ext/teek/extconf.rb +1 -1
- data/ext/teek/tcltkbridge.c +3 -0
- data/ext/teek/tcltkbridge.h +3 -0
- data/ext/teek/tkeventsource.c +195 -0
- data/ext/teek/tkphoto.c +169 -5
- data/ext/teek/tkwin.c +84 -0
- data/lib/teek/background_ractor4x.rb +32 -4
- data/lib/teek/photo.rb +232 -0
- data/lib/teek/version.rb +1 -1
- data/lib/teek.rb +3 -1
- data/sample/optcarrot/vendor/optcarrot/apu.rb +856 -0
- data/sample/optcarrot/vendor/optcarrot/config.rb +257 -0
- data/sample/optcarrot/vendor/optcarrot/cpu.rb +1162 -0
- data/sample/optcarrot/vendor/optcarrot/driver.rb +144 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb +14 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb +105 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb +153 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb +14 -0
- data/sample/optcarrot/vendor/optcarrot/nes.rb +105 -0
- data/sample/optcarrot/vendor/optcarrot/opt.rb +168 -0
- data/sample/optcarrot/vendor/optcarrot/pad.rb +92 -0
- data/sample/optcarrot/vendor/optcarrot/palette.rb +65 -0
- data/sample/optcarrot/vendor/optcarrot/ppu.rb +1468 -0
- data/sample/optcarrot/vendor/optcarrot/rom.rb +143 -0
- data/sample/optcarrot/vendor/optcarrot.rb +14 -0
- data/sample/optcarrot.rb +354 -0
- data/sample/paint/assets/bucket.png +0 -0
- data/sample/paint/assets/cursor.png +0 -0
- data/sample/paint/assets/eraser.png +0 -0
- data/sample/paint/assets/pencil.png +0 -0
- data/sample/paint/assets/spray.png +0 -0
- data/sample/paint/layer.rb +255 -0
- data/sample/paint/layer_manager.rb +179 -0
- data/sample/paint/paint_demo.rb +837 -0
- data/sample/paint/sparse_pixel_buffer.rb +202 -0
- data/sample/sdl2_demo.rb +318 -0
- metadata +29 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
module Optcarrot
|
|
2
|
+
# config manager and logger
|
|
3
|
+
class Config
|
|
4
|
+
OPTIONS = {
|
|
5
|
+
optimization: {
|
|
6
|
+
opt_ppu: {
|
|
7
|
+
type: :opts,
|
|
8
|
+
desc: "select PPU optimizations",
|
|
9
|
+
candidates: PPU::OptimizedCodeBuilder::OPTIONS,
|
|
10
|
+
default: nil,
|
|
11
|
+
},
|
|
12
|
+
opt_cpu: {
|
|
13
|
+
type: :opts,
|
|
14
|
+
desc: "select CPU optimizations",
|
|
15
|
+
candidates: CPU::OptimizedCodeBuilder::OPTIONS,
|
|
16
|
+
default: nil,
|
|
17
|
+
},
|
|
18
|
+
opt: { shortcut: %w(--opt-ppu=all --opt-cpu=all) },
|
|
19
|
+
list_opts: { type: :info, desc: "list available optimizations" },
|
|
20
|
+
dump_ppu: { type: :info, desc: "print generated PPU source code" },
|
|
21
|
+
dump_cpu: { type: :info, desc: "print generated CPU source code" },
|
|
22
|
+
load_ppu: { type: "FILE", desc: "use generated PPU source code" },
|
|
23
|
+
load_cpu: { type: "FILE", desc: "use generated CPU source code" },
|
|
24
|
+
},
|
|
25
|
+
emulation: {
|
|
26
|
+
sprite_limit: { type: :switch, desc: "enable/disable sprite limit", default: false },
|
|
27
|
+
frames: { type: :int, desc: "execute N frames (0 = no limit)", default: 0, aliases: [:f, :frame] },
|
|
28
|
+
audio_sample_rate: { type: :int, desc: "set audio sample rate", default: 44100 },
|
|
29
|
+
audio_bit_depth: { type: :int, desc: "set audio bit depth", default: 16 },
|
|
30
|
+
nestopia_palette: { type: :switch, desc: "use Nestopia palette instead of de facto", default: false },
|
|
31
|
+
},
|
|
32
|
+
driver: {
|
|
33
|
+
video: { type: :driver, desc: "select video driver", candidates: Driver::DRIVER_DB[:video].keys },
|
|
34
|
+
audio: { type: :driver, desc: "select audio driver", candidates: Driver::DRIVER_DB[:audio].keys },
|
|
35
|
+
input: { type: :driver, desc: "select input driver", candidates: Driver::DRIVER_DB[:input].keys },
|
|
36
|
+
list_drivers: { type: :info, desc: "print available drivers" },
|
|
37
|
+
sdl2: { shortcut: %w(--video=sdl2 --audio=sdl2 --input=sdl2) },
|
|
38
|
+
sfml: { shortcut: %w(--video=sfml --audio=sfml --input=sfml) },
|
|
39
|
+
headless: { shortcut: %w(--video=none --audio=none --input=none) },
|
|
40
|
+
video_output: { type: "FILE", desc: "save video to file", default: "video.EXT" },
|
|
41
|
+
audio_output: { type: "FILE", desc: "save audio to file", default: "audio.wav" },
|
|
42
|
+
show_fps: { type: :switch, desc: "show fps in the right-bottom corner", default: true },
|
|
43
|
+
key_log: { type: "FILE", desc: "use recorded input file" },
|
|
44
|
+
# key_config: { type: "KEY", desc: "key configuration" },
|
|
45
|
+
},
|
|
46
|
+
profiling: {
|
|
47
|
+
print_fps: { type: :switch, desc: "print fps of last 10 frames", default: false },
|
|
48
|
+
print_p95fps: { type: :switch, desc: "print 95th percentile fps", default: false },
|
|
49
|
+
print_fps_history: { type: :switch, desc: "print all fps values for each frame", default: false },
|
|
50
|
+
print_video_checksum: { type: :switch, desc: "print checksum of the last video output", default: false },
|
|
51
|
+
stackprof: { shortcut: "--stackprof-mode=cpu", aliases: :p },
|
|
52
|
+
stackprof_mode: { type: "MODE", desc: "run under stackprof", default: nil },
|
|
53
|
+
stackprof_output: { type: "FILE", desc: "stackprof output file", default: "stackprof-MODE.dump" }
|
|
54
|
+
},
|
|
55
|
+
misc: {
|
|
56
|
+
benchmark: { shortcut: %w(--headless --print-fps --print-video-checksum --frames 180), aliases: :b },
|
|
57
|
+
loglevel: { type: :int, desc: "set loglevel", default: 1 },
|
|
58
|
+
quiet: { shortcut: "--loglevel=0", aliases: :q },
|
|
59
|
+
verbose: { shortcut: "--loglevel=2", aliases: :v },
|
|
60
|
+
debug: { shortcut: "--loglevel=3", aliases: :d },
|
|
61
|
+
version: { type: :info, desc: "print version" },
|
|
62
|
+
help: { type: :info, desc: "print this message", aliases: :h },
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
DEFAULT_OPTIONS = {}
|
|
67
|
+
OPTIONS.each_value do |opts|
|
|
68
|
+
opts.each do |id, opt|
|
|
69
|
+
next if opt[:shortcut]
|
|
70
|
+
DEFAULT_OPTIONS[id] = opt[:default] if opt.key?(:default)
|
|
71
|
+
attr_reader id
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
attr_reader :romfile
|
|
75
|
+
|
|
76
|
+
def initialize(opt)
|
|
77
|
+
opt = Parser.new(opt).options if opt.is_a?(Array)
|
|
78
|
+
DEFAULT_OPTIONS.merge(opt).each {|id, val| instance_variable_set(:"@#{ id }", val) }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def debug(msg)
|
|
82
|
+
puts "[DEBUG] " + msg if @loglevel >= 3
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def info(msg)
|
|
86
|
+
puts "[INFO] " + msg if @loglevel >= 2
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def warn(msg)
|
|
90
|
+
puts "[WARN] " + msg if @loglevel >= 1
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def error(msg)
|
|
94
|
+
puts "[ERROR] " + msg
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def fatal(msg)
|
|
98
|
+
puts "[FATAL] " + msg
|
|
99
|
+
abort
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# command-line option parser
|
|
103
|
+
class Parser
|
|
104
|
+
def initialize(argv)
|
|
105
|
+
@argv = argv.dup
|
|
106
|
+
@options = DEFAULT_OPTIONS.dup
|
|
107
|
+
parse_option until @argv.empty?
|
|
108
|
+
error "ROM file is not given" unless @options[:romfile]
|
|
109
|
+
rescue Invalid => e
|
|
110
|
+
puts "[FATAL] #{ e }"
|
|
111
|
+
exit 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
attr_reader :options
|
|
115
|
+
|
|
116
|
+
class Invalid < RuntimeError; end
|
|
117
|
+
|
|
118
|
+
def error(msg)
|
|
119
|
+
raise Invalid, msg
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def find_option(arg)
|
|
123
|
+
OPTIONS.each_value do |opts|
|
|
124
|
+
opts.each do |id_base, opt|
|
|
125
|
+
[id_base, *opt[:aliases]].each do |id|
|
|
126
|
+
id = id.to_s.tr("_", "-")
|
|
127
|
+
return opt, id_base if id.size == 1 && arg == "-#{ id }"
|
|
128
|
+
return opt, id_base if arg == "--#{ id }"
|
|
129
|
+
return opt, id_base, true if opt[:type] == :switch && arg == "--no-#{ id }"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
return nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def parse_option
|
|
137
|
+
arg, operand = @argv.shift.split("=", 2)
|
|
138
|
+
if arg =~ /\A-(\w{2,})\z/
|
|
139
|
+
args = $1.chars.map {|a| "-#{ a }" }
|
|
140
|
+
args.last << "=" << operand if operand
|
|
141
|
+
@argv.unshift(*args)
|
|
142
|
+
return
|
|
143
|
+
end
|
|
144
|
+
opt, id, no = find_option(arg)
|
|
145
|
+
if opt
|
|
146
|
+
if opt[:shortcut]
|
|
147
|
+
@argv.unshift(*opt[:shortcut])
|
|
148
|
+
return
|
|
149
|
+
elsif opt[:type] == :info
|
|
150
|
+
send(id)
|
|
151
|
+
exit
|
|
152
|
+
elsif opt[:type] == :switch
|
|
153
|
+
error "option `#{ arg }' doesn't allow an operand" if operand
|
|
154
|
+
@options[id] = !no
|
|
155
|
+
else
|
|
156
|
+
@options[id] = parse_operand(operand, arg, opt)
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
arg = @argv.shift if arg == "--"
|
|
160
|
+
error "invalid option: `#{ arg }'" if arg && arg.start_with?("-")
|
|
161
|
+
if arg
|
|
162
|
+
error "extra argument: `#{ arg }'" if @options[:romfile]
|
|
163
|
+
@options[:romfile] = arg
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def parse_operand(operand, arg, opt)
|
|
169
|
+
type = opt[:type]
|
|
170
|
+
operand ||= @argv.shift
|
|
171
|
+
case type
|
|
172
|
+
when :opts
|
|
173
|
+
operand = operand.split(",").map {|s| s.to_sym }
|
|
174
|
+
when :driver
|
|
175
|
+
operand = operand.to_sym
|
|
176
|
+
error "unknown driver: `#{ operand }'" unless opt[:candidates].include?(operand)
|
|
177
|
+
when :int
|
|
178
|
+
begin
|
|
179
|
+
operand = Integer(operand)
|
|
180
|
+
rescue
|
|
181
|
+
error "option `#{ arg }' requires numerical operand"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
operand
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def help
|
|
188
|
+
tbl = ["Usage: #{ $PROGRAM_NAME } [OPTION]... FILE"]
|
|
189
|
+
long_name_width = 0
|
|
190
|
+
OPTIONS.each do |kind, opts|
|
|
191
|
+
tbl << "" << "#{ kind } options:"
|
|
192
|
+
opts.each do |id_base, opt|
|
|
193
|
+
short_name = [*opt[:aliases]][0]
|
|
194
|
+
switch = args = ""
|
|
195
|
+
case opt[:type]
|
|
196
|
+
when :switch then switch = "[no-]"
|
|
197
|
+
when :opts then args = "=OPTS,..."
|
|
198
|
+
when :driver then args = "=DRIVER"
|
|
199
|
+
when :int then args = "=N"
|
|
200
|
+
when String then args = "=" + opt[:type]
|
|
201
|
+
end
|
|
202
|
+
short_name = "-#{ switch }#{ short_name }, " if short_name && short_name.size == 1
|
|
203
|
+
long_name = "--" + switch + id_base.to_s.tr("_", "-") + args
|
|
204
|
+
if opt[:shortcut]
|
|
205
|
+
desc = "same as `#{ [*opt[:shortcut]].join(" ") }'"
|
|
206
|
+
else
|
|
207
|
+
desc = opt[:desc]
|
|
208
|
+
desc += " (default: #{ opt[:default] || "none" })" if opt.key?(:default)
|
|
209
|
+
end
|
|
210
|
+
long_name_width = [long_name_width, long_name.size].max
|
|
211
|
+
tbl << [short_name, long_name, desc]
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
tbl.each do |arg|
|
|
215
|
+
if arg.is_a?(String)
|
|
216
|
+
puts arg
|
|
217
|
+
else
|
|
218
|
+
short_name, long_name, desc = arg
|
|
219
|
+
puts " %4s%-*s %s" % [short_name, long_name_width, long_name, desc]
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def version
|
|
225
|
+
puts "optcarrot #{ VERSION }"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def list_drivers
|
|
229
|
+
Driver::DRIVER_DB.each do |kind, drivers|
|
|
230
|
+
puts "#{ kind } drivers: #{ drivers.keys * " " }"
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def list_opts
|
|
235
|
+
puts "CPU core optimizations:"
|
|
236
|
+
CPU::OptimizedCodeBuilder::OPTIONS.each do |opt|
|
|
237
|
+
puts " * #{ opt }"
|
|
238
|
+
end
|
|
239
|
+
puts
|
|
240
|
+
puts "PPU core optimizations:"
|
|
241
|
+
PPU::OptimizedCodeBuilder::OPTIONS.each do |opt|
|
|
242
|
+
puts " * #{ opt }"
|
|
243
|
+
end
|
|
244
|
+
puts
|
|
245
|
+
puts "(See `doc/internal.md' in detail.)"
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def dump_ppu
|
|
249
|
+
puts PPU::OptimizedCodeBuilder.new(@options[:loglevel], @options[:opt_ppu] || []).build
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def dump_cpu
|
|
253
|
+
puts CPU::OptimizedCodeBuilder.new(@options[:loglevel], @options[:opt_cpu] || []).build
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|