snes_utils 0.1.1 → 0.3.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/bin/png2snes +20 -1
- data/bin/tmx2snes +2 -1
- data/bin/vas +17 -0
- data/lib/mini_assembler/definitions.rb +16 -9
- data/lib/mini_assembler/mini_assembler.rb +236 -88
- data/lib/mini_assembler/spc700/definitions.rb +457 -455
- data/lib/mini_assembler/superfx/definitions.rb +158 -0
- data/lib/mini_assembler/wdc65816/definitions.rb +61 -59
- data/lib/png2snes/png2snes.rb +53 -21
- data/lib/snes_utils.rb +4 -4
- data/lib/tmx2snes/tmx2snes.rb +2 -7
- data/lib/vas/vas.rb +609 -0
- data/spec/mini_assembler_spec.rb +136 -0
- data/spec/spc700_spec.rb +322 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/vas_spec.rb +5 -0
- data/spec/wdc65816_spec.rb +322 -0
- metadata +21 -26
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SnesUtils
|
4
|
+
module Superfx
|
5
|
+
class Definitions
|
6
|
+
HEX_DIGIT = '[0-9a-f]'
|
7
|
+
REG = "[rR](\\d{1,2})"
|
8
|
+
LNK = "([1-4])"
|
9
|
+
HEX = "\\$?(#{HEX_DIGIT})"
|
10
|
+
HEX8 = "\\$?(#{HEX_DIGIT}{1,2})"
|
11
|
+
HEX16 = "\\$?(#{HEX_DIGIT}{1,4})"
|
12
|
+
|
13
|
+
SINGLE_OPERAND_INSTRUCTIONS = %i[imp imm4 rn rm rel lnk].freeze
|
14
|
+
DOUBLE_OPERAND_INSTRUCTIONS = %i[rn_rn rn_imm8 rn_imm16 rn_addr rn_addrl addr_rn addrl_rn].freeze
|
15
|
+
REL_INSTRUCTIONS = %i[rel].freeze
|
16
|
+
BIT_INSTRUCTIONS = %i[].freeze
|
17
|
+
SFX_INSTRUCTIONS = %i[imm4 rn rm rn_rn rn_imm8 rn_imm16 rn_addr rn_addrl addr_rn addrl_rn].freeze
|
18
|
+
MOV_INSTRUCTIONS = %i[rn_rn]
|
19
|
+
SHORT_ADDR_INSTRUCTIONS = %i[rn_addr addr_rn]
|
20
|
+
INV_DEST_INSTRUCTIONS = %i[addr_rn addrl_rn]
|
21
|
+
|
22
|
+
MODES_REGEXES = {
|
23
|
+
imp: /^$/, # nothing
|
24
|
+
imm4: /^##{HEX}$/, # #0-f
|
25
|
+
lnk: /^##{LNK}$/, # #1-4
|
26
|
+
rn: /^#{REG}$/, # R1
|
27
|
+
rm: /^\(#{REG}\)$/, # (R1)
|
28
|
+
rel: /^#{HEX16}$/i, # label / 1234
|
29
|
+
rn_rn: /^#{REG},#{REG}$/, # R1, R2
|
30
|
+
rn_imm8: /^#{REG},##{HEX8}$/, # R1, #12
|
31
|
+
rn_imm16: /^#{REG},##{HEX16}$/, # R1, #1234
|
32
|
+
rn_addr: /^#{REG},\(#{HEX16}\)$/, # R1, (1234) ; -> actual data is 1234 / 2
|
33
|
+
rn_addrl: /^#{REG},\(#{HEX16}\)$/, # R1, (1234) ; label
|
34
|
+
addr_rn: /^\(#{HEX16}\),#{REG}$/, # (1234), R1 ; -> actual data is 1234 / 2
|
35
|
+
addrl_rn: /^\(#{HEX16}\),#{REG}$/, # (1234), R1 ; label
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
OPCODES_DATA = [
|
39
|
+
# From game pak ROM to register
|
40
|
+
{ opcode: 0xef, mnemonic: 'GETB', mode: :imp, length: 1, alt: nil },
|
41
|
+
{ opcode: 0xef, mnemonic: 'GETBH', mode: :imp, length: 2, alt: 0x3d },
|
42
|
+
{ opcode: 0xef, mnemonic: 'GETBL', mode: :imp, length: 2, alt: 0x3e },
|
43
|
+
{ opcode: 0xef, mnemonic: 'GETBS', mode: :imp, length: 2, alt: 0x3f },
|
44
|
+
{ opcode: 0xdf, mnemonic: 'GETC', mode: :imp, length: 1, alt: nil },
|
45
|
+
|
46
|
+
# From game pak RAM to register
|
47
|
+
{ opcode: 0x4, mnemonic: 'LDW', mode: :rm, length: 1, alt: nil },
|
48
|
+
{ opcode: 0x4, mnemonic: 'LDB', mode: :rm, length: 1, alt: 0x3d },
|
49
|
+
{ opcode: 0xf, mnemonic: 'LM', mode: :rn_addrl, length: 4, alt: 0x3d },
|
50
|
+
{ opcode: 0xa, mnemonic: 'LMS', mode: :rn_addr, length: 3, alt: 0x3d },
|
51
|
+
|
52
|
+
# From register to game pak RAM
|
53
|
+
{ opcode: 0x3, mnemonic: 'STW', mode: :rm, length: 1, alt: nil },
|
54
|
+
{ opcode: 0x3, mnemonic: 'STB', mode: :rm, length: 2, alt: 0x3d },
|
55
|
+
{ opcode: 0xf, mnemonic: 'SM', mode: :addrl_rn, length: 4, alt: 0x3e },
|
56
|
+
{ opcode: 0xa, mnemonic: 'SMS', mode: :addr_rn, length: 3, alt: 0x3e },
|
57
|
+
{ opcode: 0x90, mnemonic: 'SBK', mode: :imp, length: 1, alt: nil },
|
58
|
+
|
59
|
+
# From register to register
|
60
|
+
{ opcode: 0x2010, mnemonic: 'MOVE', mode: :rn_rn, length: 2, alt: nil },
|
61
|
+
{ opcode: 0x20b0, mnemonic: 'MOVES', mode: :rn_rn, length: 2, alt: nil },
|
62
|
+
|
63
|
+
# Immediate data to register
|
64
|
+
{ opcode: 0xf, mnemonic: 'IWT', mode: :rn_imm16, length: 3, alt: nil },
|
65
|
+
{ opcode: 0xa, mnemonic: 'IBT', mode: :rn_imm8, length: 2, alt: nil },
|
66
|
+
|
67
|
+
# Arithmetic operations
|
68
|
+
{ opcode: 0x5, mnemonic: 'ADD', mode: :rn, length: 1, alt: nil },
|
69
|
+
{ opcode: 0x5, mnemonic: 'ADD', mode: :imm4, length: 2, alt: 0x3e },
|
70
|
+
{ opcode: 0x5, mnemonic: 'ADC', mode: :rn, length: 2, alt: 0x3d },
|
71
|
+
{ opcode: 0x5, mnemonic: 'ADC', mode: :imm4, length: 2, alt: 0x3f },
|
72
|
+
|
73
|
+
{ opcode: 0x6, mnemonic: 'SUB', mode: :rn, length: 1, alt: nil },
|
74
|
+
{ opcode: 0x6, mnemonic: 'SUB', mode: :imm4, length: 2, alt: 0x3e },
|
75
|
+
{ opcode: 0x6, mnemonic: 'SBC', mode: :rn, length: 2, alt: 0x3d },
|
76
|
+
|
77
|
+
{ opcode: 0x6, mnemonic: 'CMP', mode: :rn, length: 2, alt: 0x3f },
|
78
|
+
|
79
|
+
{ opcode: 0x8, mnemonic: 'MULT', mode: :rn, length: 1, alt: nil },
|
80
|
+
{ opcode: 0x8, mnemonic: 'MULT', mode: :imm4, length: 2, alt: 0x3e },
|
81
|
+
{ opcode: 0x8, mnemonic: 'UMULT', mode: :rn, length: 2, alt: 0x3d },
|
82
|
+
{ opcode: 0x8, mnemonic: 'UMULT', mode: :imm4, length: 2, alt: 0x3f },
|
83
|
+
{ opcode: 0x9f, mnemonic: 'FMULT', mode: :imp, length: 1, alt: nil },
|
84
|
+
{ opcode: 0x9f, mnemonic: 'LMULT', mode: :imp, length: 2, alt: 0x3d },
|
85
|
+
|
86
|
+
{ opcode: 0x96, mnemonic: 'DIV2', mode: :imp, length: 2, alt: 0x3d },
|
87
|
+
|
88
|
+
{ opcode: 0xd, mnemonic: 'INC', mode: :rn, length: 1, alt: nil },
|
89
|
+
{ opcode: 0xe, mnemonic: 'DEC', mode: :rn, length: 1, alt: nil },
|
90
|
+
|
91
|
+
# Logical operations
|
92
|
+
{ opcode: 0x7, mnemonic: 'AND', mode: :rn, length: 1, alt: nil },
|
93
|
+
{ opcode: 0x7, mnemonic: 'AND', mode: :imm4, length: 2, alt: 0x3e },
|
94
|
+
{ opcode: 0xc, mnemonic: 'OR', mode: :rn, length: 1, alt: nil },
|
95
|
+
{ opcode: 0xc, mnemonic: 'OR', mode: :imm4, length: 2, alt: 0x3e },
|
96
|
+
{ opcode: 0x4f, mnemonic: 'NOT', mode: :imp, length: 1, alt: nil },
|
97
|
+
{ opcode: 0xc, mnemonic: 'XOR', mode: :rn, length: 2, alt: 0x3d },
|
98
|
+
{ opcode: 0xc, mnemonic: 'XOR', mode: :imm4, length: 2, alt: 0x3f },
|
99
|
+
{ opcode: 0x7, mnemonic: 'BIC', mode: :rn, length: 2, alt: 0x3d },
|
100
|
+
{ opcode: 0x7, mnemonic: 'BIC', mode: :imm4, length: 2, alt: 0x3f },
|
101
|
+
|
102
|
+
# Shift
|
103
|
+
{ opcode: 0x96, mnemonic: 'ASR', mode: :imp, length: 1, alt: nil },
|
104
|
+
{ opcode: 0x03, mnemonic: 'LSR', mode: :imp, length: 1, alt: nil },
|
105
|
+
{ opcode: 0x04, mnemonic: 'ROL', mode: :imp, length: 1, alt: nil },
|
106
|
+
{ opcode: 0x97, mnemonic: 'ROR', mode: :imp, length: 1, alt: nil },
|
107
|
+
|
108
|
+
# Byte transfer
|
109
|
+
{ opcode: 0xc0, mnemonic: 'HIB', mode: :imp, length: 1, alt: nil },
|
110
|
+
{ opcode: 0x9e, mnemonic: 'LOB', mode: :imp, length: 1, alt: nil },
|
111
|
+
{ opcode: 0x70, mnemonic: 'MERGE', mode: :imp, length: 1, alt: nil },
|
112
|
+
{ opcode: 0x95, mnemonic: 'SEX', mode: :imp, length: 1, alt: nil },
|
113
|
+
{ opcode: 0x4d, mnemonic: 'SWAP', mode: :imp, length: 1, alt: nil },
|
114
|
+
|
115
|
+
# Jump, branch and loop
|
116
|
+
{ opcode: 0x9, mnemonic: 'JMP', mode: :rn, length: 1, alt: nil },
|
117
|
+
{ opcode: 0x9, mnemonic: 'LJMP', mode: :rn, length: 2, alt: 0x3d },
|
118
|
+
{ opcode: 0x05, mnemonic: 'BRA', mode: :rel, length: 2, alt: nil },
|
119
|
+
{ opcode: 0x06, mnemonic: 'BGE', mode: :rel, length: 2, alt: nil },
|
120
|
+
{ opcode: 0x07, mnemonic: 'BLT', mode: :rel, length: 2, alt: nil },
|
121
|
+
{ opcode: 0x08, mnemonic: 'BNE', mode: :rel, length: 2, alt: nil },
|
122
|
+
{ opcode: 0x09, mnemonic: 'BEQ', mode: :rel, length: 2, alt: nil },
|
123
|
+
{ opcode: 0x0a, mnemonic: 'BPL', mode: :rel, length: 2, alt: nil },
|
124
|
+
{ opcode: 0x0b, mnemonic: 'BMI', mode: :rel, length: 2, alt: nil },
|
125
|
+
{ opcode: 0x0c, mnemonic: 'BCC', mode: :rel, length: 2, alt: nil },
|
126
|
+
{ opcode: 0x0d, mnemonic: 'BCS', mode: :rel, length: 2, alt: nil },
|
127
|
+
{ opcode: 0x0e, mnemonic: 'BVC', mode: :rel, length: 2, alt: nil },
|
128
|
+
{ opcode: 0x0f, mnemonic: 'BVS', mode: :rel, length: 2, alt: nil },
|
129
|
+
{ opcode: 0x3c, mnemonic: 'LOOP', mode: :imp, length: 1, alt: nil },
|
130
|
+
{ opcode: 0x9, mnemonic: 'LINK', mode: :imm4, length: 1, alt: nil },
|
131
|
+
|
132
|
+
# Bank set-up
|
133
|
+
{ opcode: 0xdf, mnemonic: 'ROMB', mode: :imp, length: 2, alt: 0x3f },
|
134
|
+
{ opcode: 0xdf, mnemonic: 'RAMB', mode: :imp, length: 2, alt: 0x3e },
|
135
|
+
|
136
|
+
# Plot related
|
137
|
+
{ opcode: 0x4e, mnemonic: 'CMODE', mode: :imp, length: 2, alt: 0x3d },
|
138
|
+
{ opcode: 0x4e, mnemonic: 'COLOR', mode: :imp, length: 1, alt: nil },
|
139
|
+
{ opcode: 0x4c, mnemonic: 'PLOT', mode: :imp, length: 1, alt: nil },
|
140
|
+
{ opcode: 0x4c, mnemonic: 'RPIX', mode: :imp, length: 2, alt: 0x3d },
|
141
|
+
|
142
|
+
# Prefix flag
|
143
|
+
{ opcode: 0x3d, mnemonic: 'ALT1', mode: :imp, length: 1, alt: nil },
|
144
|
+
{ opcode: 0x3e, mnemonic: 'ALT2', mode: :imp, length: 1, alt: nil },
|
145
|
+
{ opcode: 0x3f, mnemonic: 'ALT3', mode: :imp, length: 1, alt: nil },
|
146
|
+
|
147
|
+
# Prefix register
|
148
|
+
{ opcode: 0xb, mnemonic: 'FROM', mode: :rn, length: 1, alt: nil },
|
149
|
+
{ opcode: 0x1, mnemonic: 'TO', mode: :rn, length: 1, alt: nil },
|
150
|
+
{ opcode: 0x2, mnemonic: 'WITH', mode: :rn, length: 1, alt: nil },
|
151
|
+
|
152
|
+
# GSU Control
|
153
|
+
{ opcode: 0x02, mnemonic: 'CACHE', mode: :imp, length: 1, alt: nil },
|
154
|
+
{ opcode: 0x01, mnemonic: 'NOP', mode: :imp, length: 1, alt: nil },
|
155
|
+
{ opcode: 0x00, mnemonic: 'STOP', mode: :imp, length: 1, alt: nil }].freeze
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SnesUtils
|
2
4
|
module Wdc65816
|
3
5
|
class Definitions
|
@@ -6,70 +8,70 @@ module SnesUtils
|
|
6
8
|
HEX16 = "\\$?(#{HEX_DIGIT}{3,4})"
|
7
9
|
HEX24 = "\\$?(#{HEX_DIGIT}{5,6})"
|
8
10
|
|
9
|
-
SINGLE_OPERAND_INSTRUCTIONS = [
|
10
|
-
DOUBLE_OPERAND_INSTRUCTIONS = [:bm]
|
11
|
-
REL_INSTRUCTIONS = [
|
12
|
-
BIT_INSTRUCTIONS = []
|
11
|
+
SINGLE_OPERAND_INSTRUCTIONS = %i[imm iml imm8 imm16 sr dp dpx dpy idp idx idy idl idly isy abs abx aby abl alx ind iax ial rel rell].freeze
|
12
|
+
DOUBLE_OPERAND_INSTRUCTIONS = [:bm].freeze
|
13
|
+
REL_INSTRUCTIONS = %i[rel rell].freeze
|
14
|
+
BIT_INSTRUCTIONS = [].freeze
|
13
15
|
|
14
16
|
MODES_REGEXES = {
|
15
|
-
acc:
|
16
|
-
imp:
|
17
|
-
imm:
|
18
|
-
iml:
|
19
|
-
imm8:
|
17
|
+
acc: /^$/,
|
18
|
+
imp: /^$/,
|
19
|
+
imm: /^#{HEX8}$/i,
|
20
|
+
iml: /^#{HEX16}$/i,
|
21
|
+
imm8: /^##{HEX8}$/i,
|
20
22
|
imm16: /^##{HEX16}$/i,
|
21
|
-
sr:
|
22
|
-
dp:
|
23
|
-
dpx:
|
24
|
-
dpy:
|
25
|
-
idp:
|
26
|
-
idx:
|
27
|
-
idy:
|
28
|
-
idl:
|
29
|
-
idly:
|
30
|
-
isy:
|
31
|
-
abs:
|
32
|
-
abx:
|
33
|
-
aby:
|
34
|
-
abl:
|
35
|
-
alx:
|
36
|
-
ind:
|
37
|
-
iax:
|
38
|
-
ial:
|
39
|
-
rel:
|
40
|
-
rell:
|
41
|
-
bm:
|
42
|
-
}
|
23
|
+
sr: /^#{HEX8},S$/i,
|
24
|
+
dp: /^#{HEX8}$/i,
|
25
|
+
dpx: /^#{HEX8},X$/i,
|
26
|
+
dpy: /^#{HEX8},Y$/i,
|
27
|
+
idp: /^\(#{HEX8}\)$/i,
|
28
|
+
idx: /^\(#{HEX8},X\)$/i,
|
29
|
+
idy: /^\(#{HEX8}\),Y$/i,
|
30
|
+
idl: /^\[#{HEX8}\]$/i,
|
31
|
+
idly: /^\[#{HEX8}\],Y$/i,
|
32
|
+
isy: /^\(#{HEX8},S\),Y$/i,
|
33
|
+
abs: /^#{HEX16}$/i,
|
34
|
+
abx: /^#{HEX16},X$/i,
|
35
|
+
aby: /^#{HEX16},Y$/i,
|
36
|
+
abl: /^#{HEX24}$/i,
|
37
|
+
alx: /^#{HEX24},X$/i,
|
38
|
+
ind: /^\(#{HEX16}\)$/i,
|
39
|
+
iax: /^\(#{HEX16},X\)$/i,
|
40
|
+
ial: /^\[#{HEX16}\]$/i,
|
41
|
+
rel: /^#{HEX16}$/i,
|
42
|
+
rell: /^#{HEX16}$/i,
|
43
|
+
bm: /^#{HEX8},#{HEX8}$/i
|
44
|
+
}.freeze
|
43
45
|
|
44
46
|
MODES_FORMATS = {
|
45
|
-
acc:
|
46
|
-
imp:
|
47
|
-
imm:
|
48
|
-
iml:
|
49
|
-
imm8:
|
50
|
-
imm16:
|
51
|
-
sr:
|
52
|
-
dp:
|
53
|
-
dpx:
|
54
|
-
dpy:
|
55
|
-
idp:
|
56
|
-
idx:
|
57
|
-
idy:
|
58
|
-
idl:
|
59
|
-
idly:
|
60
|
-
isy:
|
61
|
-
abs:
|
62
|
-
abx:
|
63
|
-
aby:
|
64
|
-
abl:
|
65
|
-
alx:
|
66
|
-
ind:
|
67
|
-
iax:
|
68
|
-
ial:
|
69
|
-
rel:
|
70
|
-
rell:
|
71
|
-
bm:
|
72
|
-
}
|
47
|
+
acc: '%s',
|
48
|
+
imp: '%s',
|
49
|
+
imm: '%s %02X',
|
50
|
+
iml: '%s %02X',
|
51
|
+
imm8: '%s #%02X',
|
52
|
+
imm16: '%s #%04X',
|
53
|
+
sr: '%s %02X,S',
|
54
|
+
dp: '%s %02X',
|
55
|
+
dpx: '%s %02X,X',
|
56
|
+
dpy: '%s %02X,Y',
|
57
|
+
idp: '%s (%02X)',
|
58
|
+
idx: '%s (%02X,X)',
|
59
|
+
idy: '%s (%02X),Y',
|
60
|
+
idl: '%s [%02X]',
|
61
|
+
idly: '%s [%02X],Y',
|
62
|
+
isy: '%s (%02X,S),Y',
|
63
|
+
abs: '%s %04X',
|
64
|
+
abx: '%s %04X,X',
|
65
|
+
aby: '%s %04X,Y',
|
66
|
+
abl: '%s %06X',
|
67
|
+
alx: '%s %06X,X',
|
68
|
+
ind: '%s (%04X)',
|
69
|
+
iax: '%s (%04X,X)',
|
70
|
+
ial: '%s [%04X]',
|
71
|
+
rel: '%s %04X {%s}',
|
72
|
+
rell: '%s %04X {%s}',
|
73
|
+
bm: '%s %02X,%02X'
|
74
|
+
}.freeze
|
73
75
|
|
74
76
|
OPCODES_DATA = [{ opcode: 0x61, mnemonic: 'ADC', mode: :idx, length: 2 },
|
75
77
|
{ opcode: 0x63, mnemonic: 'ADC', mode: :sr, length: 2 },
|
data/lib/png2snes/png2snes.rb
CHANGED
@@ -1,22 +1,34 @@
|
|
1
1
|
module SnesUtils
|
2
2
|
class Png2Snes
|
3
|
-
|
3
|
+
CHAR_SIZE = 8
|
4
|
+
|
5
|
+
def initialize(file_path, bpp:4, alpha:nil, mode7: false, m7_palette_offset: nil)
|
4
6
|
@file_path = file_path
|
5
7
|
@file_dir = File.dirname(@file_path)
|
6
8
|
@file_name = File.basename(@file_path, File.extname(@file_path))
|
7
9
|
@image = ChunkyPNG::Image.from_file(@file_path)
|
8
|
-
@pixels = pixels_to_bgr5
|
9
10
|
|
11
|
+
@mode7 = mode7
|
12
|
+
|
13
|
+
raise ArgumentError, 'Image width and height must be a multiple of sprite size' if (@image.width % CHAR_SIZE != 0) or (@image.height % CHAR_SIZE != 0)
|
14
|
+
|
15
|
+
@pixels = pixels_to_bgr5
|
10
16
|
@palette = @pixels.uniq
|
11
|
-
@char_size = 8
|
12
17
|
|
13
|
-
|
14
|
-
|
18
|
+
if @mode7
|
19
|
+
raise ArgumentError, 'mode 7 palette offset must be multiple of 16' if m7_palette_offset % 16 != 0
|
20
|
+
raise ArgumentError, 'mode 7 palette offset must be less than 112' if m7_palette_offset > 112
|
21
|
+
@m7_palette_offset = m7_palette_offset
|
15
22
|
|
16
|
-
|
23
|
+
unshift_alpha(alpha) if alpha
|
24
|
+
fill_palette
|
25
|
+
else
|
26
|
+
raise ArgumentError, 'BPP must be 2, 4, or 8' unless [2, 4, 8].include? bpp
|
27
|
+
@bpp = bpp
|
17
28
|
|
18
|
-
|
19
|
-
|
29
|
+
unshift_alpha(alpha) if alpha
|
30
|
+
fill_palette
|
31
|
+
end
|
20
32
|
end
|
21
33
|
|
22
34
|
def pixels_to_bgr5
|
@@ -29,17 +41,22 @@ module SnesUtils
|
|
29
41
|
end
|
30
42
|
end
|
31
43
|
|
32
|
-
def
|
44
|
+
def unshift_alpha(alpha)
|
45
|
+
@palette.unshift(alpha)
|
33
46
|
end
|
34
47
|
|
35
48
|
def fill_palette
|
36
|
-
target_size = 2**@bpp
|
49
|
+
target_size = @mode7 ? mode_7_pal_size : 2**@bpp
|
37
50
|
missing_colors = target_size - @palette.count
|
38
51
|
raise ArgumentError, "Palette size too large for target BPP (#{@palette.count})" if missing_colors < 0
|
39
52
|
|
40
53
|
@palette += [0] * missing_colors
|
41
54
|
end
|
42
55
|
|
56
|
+
def mode_7_pal_size
|
57
|
+
128 - @m7_palette_offset
|
58
|
+
end
|
59
|
+
|
43
60
|
def write hex, file_path
|
44
61
|
File.open(file_path, 'w+b') do |file|
|
45
62
|
file.write([hex.join].pack('H*'))
|
@@ -48,7 +65,7 @@ module SnesUtils
|
|
48
65
|
|
49
66
|
def write_palette
|
50
67
|
palette_hex = @palette.map { |c| ('%04x' % c).scan(/.{2}/).reverse.join }
|
51
|
-
write palette_hex, File.expand_path("#{@file_name}
|
68
|
+
write palette_hex, File.expand_path("#{@file_name}.pal", @file_dir)
|
52
69
|
end
|
53
70
|
|
54
71
|
def pixel_indices
|
@@ -60,16 +77,20 @@ module SnesUtils
|
|
60
77
|
def extract_sprites
|
61
78
|
pixel_idx = pixel_indices
|
62
79
|
|
63
|
-
sprite_per_row = @image.width /
|
64
|
-
sprite_per_col = @image.height /
|
80
|
+
sprite_per_row = @image.width / CHAR_SIZE
|
81
|
+
sprite_per_col = @image.height / CHAR_SIZE
|
65
82
|
sprite_per_sheet = sprite_per_row * sprite_per_col
|
66
83
|
|
67
84
|
sprites = []
|
68
85
|
(0..sprite_per_sheet-1).each do |s|
|
69
86
|
sprite = []
|
70
|
-
(0
|
71
|
-
offset = (s/sprite_per_row)*sprite_per_row *
|
72
|
-
|
87
|
+
(0..CHAR_SIZE-1).each do |r|
|
88
|
+
offset = (s/sprite_per_row)*sprite_per_row * CHAR_SIZE**2 + s % sprite_per_row * CHAR_SIZE
|
89
|
+
if @mode7
|
90
|
+
sprite += @pixels[offset + r*sprite_per_row*CHAR_SIZE, CHAR_SIZE]
|
91
|
+
else
|
92
|
+
sprite += pixel_idx[offset + r*sprite_per_row*CHAR_SIZE, CHAR_SIZE]
|
93
|
+
end
|
73
94
|
end
|
74
95
|
sprites.push(sprite)
|
75
96
|
end
|
@@ -87,7 +108,11 @@ module SnesUtils
|
|
87
108
|
end
|
88
109
|
|
89
110
|
def write_image
|
90
|
-
|
111
|
+
@mode7 ? write_image_m7 : write_image_m06
|
112
|
+
end
|
113
|
+
|
114
|
+
def write_image_m06
|
115
|
+
sprite_per_row = @image.width / CHAR_SIZE
|
91
116
|
sprites = extract_sprites
|
92
117
|
sprites_bitplanes = sprites.map { |s| extract_bitplanes s }
|
93
118
|
|
@@ -97,9 +122,9 @@ module SnesUtils
|
|
97
122
|
|
98
123
|
bitplane_bits = ""
|
99
124
|
sprite_bitplane_pairs.each do |bitplane|
|
100
|
-
(0
|
101
|
-
offset = r
|
102
|
-
bitplane_bits += bitplane[0][offset,
|
125
|
+
(0..CHAR_SIZE-1).each do |r|
|
126
|
+
offset = r*CHAR_SIZE
|
127
|
+
bitplane_bits += bitplane[0][offset, CHAR_SIZE].join + bitplane[1][offset, CHAR_SIZE].join
|
103
128
|
end
|
104
129
|
end
|
105
130
|
image_bits += bitplane_bits
|
@@ -107,8 +132,15 @@ module SnesUtils
|
|
107
132
|
end
|
108
133
|
|
109
134
|
image_hex = image_bits.scan(/.{8}/).map { |b| "%02x" % b.to_i(2) }
|
110
|
-
write image_hex, File.expand_path("#{@file_name}.
|
135
|
+
write image_hex, File.expand_path("#{@file_name}.tiles", @file_dir)
|
111
136
|
end
|
112
137
|
|
138
|
+
def write_image_m7
|
139
|
+
sprites = extract_sprites
|
140
|
+
|
141
|
+
indices = sprites.flatten.map { |color| "%02x" % (@palette.index(color) + @m7_palette_offset) }
|
142
|
+
|
143
|
+
write indices, File.expand_path("#{@file_name}.tiles", @file_dir)
|
144
|
+
end
|
113
145
|
end
|
114
146
|
end
|
data/lib/snes_utils.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'readline'
|
2
2
|
require 'chunky_png'
|
3
|
-
require '
|
4
|
-
require 'nokogiri'
|
5
|
-
|
6
|
-
require 'byebug'
|
3
|
+
require 'csv'
|
7
4
|
|
8
5
|
require 'mini_assembler/mini_assembler'
|
9
6
|
require 'mini_assembler/definitions'
|
10
7
|
require 'mini_assembler/wdc65816/definitions'
|
11
8
|
require 'mini_assembler/spc700/definitions'
|
9
|
+
require 'mini_assembler/superfx/definitions'
|
12
10
|
require 'png2snes/png2snes'
|
13
11
|
require 'tmx2snes/tmx2snes'
|
14
12
|
|
13
|
+
require 'vas/vas'
|
14
|
+
|
15
15
|
module SnesUtils
|
16
16
|
end
|
data/lib/tmx2snes/tmx2snes.rb
CHANGED
@@ -14,14 +14,9 @@ module SnesUtils
|
|
14
14
|
tnm = big_char ? 2 : 1 # big_char : 16x16 tiles. otherwise, 8x8 tiles
|
15
15
|
row_offset = 16 * (tnm - 1) # Skip a row in case of 16x16 tiles ( tile #9 starts at index 32)
|
16
16
|
|
17
|
-
|
18
|
-
csv_node = doc.xpath('//data').children.first.to_s
|
19
|
-
|
20
|
-
csv = csv_node.split("\n").compact.reject { |e| e.empty? }.map { |row| row.split(',') }
|
21
|
-
|
22
|
-
csv.each do |row|
|
17
|
+
CSV.foreach(@file_path) do |row|
|
23
18
|
raise if row.length != 32
|
24
|
-
@tilemap += row.map { |r| (r.to_i
|
19
|
+
@tilemap += row.map { |r| (r.to_i)*tnm + row_offset * ((r.to_i)/8).to_i }
|
25
20
|
end
|
26
21
|
|
27
22
|
raise if @tilemap.length != 32*32
|