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.
@@ -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 = [:imm, :iml, :imm8, :imm16, :sr, :dp, :dpx, :dpy, :idp, :idx, :idy, :idl, :idly, :isy, :abs, :abx, :aby, :abl, :alx, :ind, :iax, :ial, :rel, :rell]
10
- DOUBLE_OPERAND_INSTRUCTIONS = [:bm]
11
- REL_INSTRUCTIONS = [:rel, :rell]
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: /^#{HEX8}$/i,
18
- iml: /^#{HEX16}$/i,
19
- imm8: /^##{HEX8}$/i,
17
+ acc: /^$/,
18
+ imp: /^$/,
19
+ imm: /^#{HEX8}$/i,
20
+ iml: /^#{HEX16}$/i,
21
+ imm8: /^##{HEX8}$/i,
20
22
  imm16: /^##{HEX16}$/i,
21
- sr: /^#{HEX8},S$/i,
22
- dp: /^#{HEX8}$/i,
23
- dpx: /^#{HEX8},X$/i,
24
- dpy: /^#{HEX8},Y$/i,
25
- idp: /^\(#{HEX8}\)$/i,
26
- idx: /^\(#{HEX8},X\)$/i,
27
- idy: /^\(#{HEX8}\),Y$/i,
28
- idl: /^\[#{HEX8}\]$/i,
29
- idly: /^\[#{HEX8}\],Y$/i,
30
- isy: /^\(#{HEX8},S\),Y$/i,
31
- abs: /^#{HEX16}$/i,
32
- abx: /^#{HEX16},X$/i,
33
- aby: /^#{HEX16},Y$/i,
34
- abl: /^#{HEX24}$/i,
35
- alx: /^#{HEX24},X$/i,
36
- ind: /^\(#{HEX16}\)$/i,
37
- iax: /^\(#{HEX16},X\)$/i,
38
- ial: /^\[#{HEX16}\]$/i,
39
- rel: /^#{HEX16}$/i,
40
- rell: /^#{HEX16}$/i,
41
- bm: /^#{HEX8},#{HEX8}$/i
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: "%s",
46
- imp: "%s",
47
- imm: "%s %02X",
48
- iml: "%s %02X",
49
- imm8: "%s #%02X",
50
- imm16: "%s #%04X",
51
- sr: "%s %02X,S",
52
- dp: "%s %02X",
53
- dpx: "%s %02X,X",
54
- dpy: "%s %02X,Y",
55
- idp: "%s (%02X)",
56
- idx: "%s (%02X,X)",
57
- idy: "%s (%02X),Y",
58
- idl: "%s [%02X]",
59
- idly: "%s [%02X],Y",
60
- isy: "%s (%02X,S),Y",
61
- abs: "%s %04X",
62
- abx: "%s %04X,X",
63
- aby: "%s %04X,Y",
64
- abl: "%s %06X",
65
- alx: "%s %06X,X",
66
- ind: "%s (%04X)",
67
- iax: "%s (%04X,X)",
68
- ial: "%s [%04X]",
69
- rel: "%s %04X {%s}",
70
- rell: "%s %04X {%s}",
71
- bm: "%s %02X,%02X"
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 },
@@ -1,22 +1,34 @@
1
1
  module SnesUtils
2
2
  class Png2Snes
3
- def initialize(file_path, bpp:4, alpha:nil)
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
- raise ArgumentError, 'BPP must be 2, 4, or 8' unless [2, 4, 8].include? bpp
14
- @bpp = bpp
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
- 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)
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
- alpha_first if alpha
19
- fill_palette
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 alpha_first
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}-pal.bin", @file_dir)
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 / @char_size
64
- sprite_per_col = @image.height / @char_size
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..@char_size-1).each do |r|
71
- offset = (s/sprite_per_row)*sprite_per_row * @char_size**2 + s % sprite_per_row * @char_size
72
- sprite += pixel_idx[offset + r*sprite_per_row*@char_size, @char_size]
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
- sprite_per_row = @image.width / @char_size
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..@char_size-1).each do |r|
101
- offset = r*@char_size
102
- bitplane_bits += bitplane[0][offset, @char_size].join + bitplane[1][offset, @char_size].join
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}.bin", @file_dir)
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 'matrix'
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
@@ -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
- doc = Nokogiri::XML(File.open(@file_path))
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 - 1)*tnm + row_offset * ((r.to_i - 1)/8).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