Class: Sabrina::Sprite
- Inherits:
-
Bytestream
- Object
- Bytestream
- Sabrina::Sprite
- Defined in:
- lib/sabrina/sprite.rb
Overview
Instance Attribute Summary collapse
-
#palette ⇒ Object
Gets or sets the default palette for RGB output.
Attributes inherited from Bytestream
#filename, #index, #last_write, #rom, #table, #work_dir
Class Method Summary collapse
- .from_canvas(c, palette = Palette.empty, h = {}) ⇒ Sprite
-
.from_png(file, palette = Palette.empty, h = {}) ⇒ Sprite
Generates a sprite from a PNG file and optionally attempts to match the colors to the provided Palette.
-
.from_rgb(rgb, width = 64, palette = Palette.empty, h = {}) ⇒ Sprite
Generates a sprite from a stream of bytes following the
0xRRGGBB
format with the providedwidth
, optionally matching the colors to the supplied Palette (and failing if the sprite dimensions are not multiples of 8 or the total number of colors in the image and the palette exceeds 16). -
.from_rom(rom, offset, width = 64, h = {}) ⇒ Sprite
Same as Bytestream::ByteInput#from_rom, but supplies no
length
(due to implicit Lz77 mode) and supports a width parameter for the resulting picture. -
.from_table(rom, table, index, width = 64, h = {}) ⇒ Sprite
Same as Bytestream::ByteInput#from_table_as_pointer, but also supports a width parameter for the resulting picture.
Instance Method Summary collapse
-
#generate_bytes ⇒ String
Converts the internal representation to a GBA-compatible stream of bytes.
-
#initialize(h = {}) ⇒ Sprite
constructor
Same as Bytestream#initialize, but with
:lz77
and:pointer_mode
set to true by default and support for the following extra options. -
#justify ⇒ self
Crops or repeats the sprite vertically until it meets the current ROM’s frame count, assuming 64x64 pixels per frame.
-
#present ⇒ Array
(also: #to_a)
Returns an array of characters that represent the palette index of each pixel in hexadecimal format.
- #rom=(p_rom) ⇒ Object
-
#to_ascii(width_multiplier = 2) ⇒ String
Outputs the sprite as ASCII art with each pixel represented by the hexadecimal value of its palette index.
-
#to_canvas(pal = @palette) ⇒ Canvas
Converts the internal representation to a Canvas object using the default palette or the provided one (and failing if neither is present.).
-
#to_png(file, dir = '', pal = @palette) ⇒ Object
(also: #to_file)
Saves the internal representation to a PNG file (appending the file extension if absent) using the default palette or the provided one (and failing if neither is present.).
-
#to_rgb(pal = @palette) ⇒ String
Converts the internal representation to a stream of
0xRRGGBB
bytes using the default palette or the provided one (and failing if neither is present.). -
#to_s ⇒ String
A blurb showing the sprite dimensions.
Methods inherited from Bytestream
#lz77_mode, #offset, #offset=, parse_offset, #pointer, #string_mode
Methods included from Bytestream::ByteInput
#from_bytes, #from_hex, #from_rom, #from_rom_as_lz77, #from_table, #from_table_as_pointer
Methods included from Bytestream::RomOperations
#calculate_length, #clear_cache, #reload_from_rom, #write_to_rom
Methods included from Bytestream::ByteOutput
#to_b, #to_bytes, #to_hex, #to_hex_reverse, #to_i, #to_lz77
Constructor Details
#initialize(h = {}) ⇒ Sprite
Same as Bytestream#initialize, but with :lz77
and :pointer_mode
set to true by default and support for the following extra options.
120 121 122 123 124 125 126 127 128 |
# File 'lib/sabrina/sprite.rb', line 120 def initialize(h = {}) @lz77 = true @pointer_mode = true @width = 64 @palette = nil super end |
Instance Attribute Details
#palette ⇒ Object
Gets or sets the default palette for RGB output. Note that this will not cause the palette to also be automatically written to ROM on sprite Bytestream::RomOperations#write_to_rom.
11 12 13 |
# File 'lib/sabrina/sprite.rb', line 11 def palette @palette end |
Class Method Details
.from_canvas(c, palette = Palette.empty, h = {}) ⇒ Sprite
66 67 68 |
# File 'lib/sabrina/sprite.rb', line 66 def from_canvas(c, palette = Palette.empty, h = {}) from_rgb(c.to_rgb_stream, c.width, palette, h) end |
.from_png(file, palette = Palette.empty, h = {}) ⇒ Sprite
51 52 53 54 55 |
# File 'lib/sabrina/sprite.rb', line 51 def from_png(file, palette = Palette.empty, h = {}) c = ChunkyPNG::Canvas.from_file(file) from_canvas(c, palette, h) end |
.from_rgb(rgb, width = 64, palette = Palette.empty, h = {}) ⇒ Sprite
Generates a sprite from a stream of bytes following the 0xRRGGBB
format with the provided width
, optionally matching the colors to the supplied Palette (and failing if the sprite dimensions are not multiples of 8 or the total number of colors in the image and the palette exceeds 16).
It is important to remember that while the resulting image will be ready for saving to PNG, writing it to a ROM will not save the color data by itself. The generated palette (accessible via #palette) should be written separately. The Spritesheet plugin should take care of that for you.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/sabrina/sprite.rb', line 87 def from_rgb(rgb, width = 64, palette = Palette.empty, h = {}) fail 'RGB stream length must divide by 3.' unless rgb.length % 3 == 0 unless width % 8 == 0 && (rgb.length / 3 / width) % 8 == 0 fail 'Sprite dimensions must be divisible by 8.' end out_array = [] until rgb.empty? pixel = rgb.slice!(0, 3).unpack('CCC') palette.add(pixel) unless palette.index_of(pixel) out_array << palette.index_of(pixel).to_s(16).upcase end h.merge!( representation: out_array, width: width, palette: palette ) new(h) end |
.from_rom(rom, offset, width = 64, h = {}) ⇒ Sprite
Same as Bytestream::ByteInput#from_rom, but supplies no length
(due to implicit Lz77 mode) and supports a width parameter for the resulting picture.
34 35 36 37 |
# File 'lib/sabrina/sprite.rb', line 34 def from_rom(rom, offset, width = 64, h = {}) h.merge!(width: width) super(rom, offset, nil, h) end |
.from_table(rom, table, index, width = 64, h = {}) ⇒ Sprite
Same as Bytestream::ByteInput#from_table_as_pointer, but also supports a width parameter for the resulting picture.
21 22 23 24 |
# File 'lib/sabrina/sprite.rb', line 21 def from_table(rom, table, index, width = 64, h = {}) h.merge!(width: width) from_table_as_pointer(rom, table, index, h) end |
Instance Method Details
#generate_bytes ⇒ String
Some breakage with number 360, is this the culprit?
Converts the internal representation to a GBA-compatible stream of bytes.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/sabrina/sprite.rb', line 168 def generate_bytes in_array = [] present.join('').scan(/(.)(.)/) { |x, y| in_array += [y, x] } column_num = @width / 8 out_array = [] loop do break if in_array.empty? columns = [[]] * column_num until columns[0].length == 8 * 8 column_num.times { |i| columns[i] += in_array.slice!(0, 8) } end # Filled one block out_array += columns.slice!(0) until columns.empty? end Bytestream.from_hex(out_array.join('')).to_b end |
#justify ⇒ self
Crops or repeats the sprite vertically until it meets the current ROM’s frame count, assuming 64x64 pixels per frame.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/sabrina/sprite.rb', line 212 def justify frame_count = if @table.to_sym == :front_table @rom.special_frames.fetch(@index, @rom.frames).first else @rom.special_frames.fetch(@index, @rom.frames).last end h = { lz77: false } target = frame_count * 64 * 64 old_rep = @representation.dup if @representation.length < target @representation += old_rep until @representation.length >= target h = { lz77: true } elsif @representation.length > target @representation.slice!(0, target) h = { lz77: true } end clear_cache(h) end |
#present ⇒ Array Also known as: to_a
Returns an array of characters that represent the palette index of each pixel in hexadecimal format.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/sabrina/sprite.rb', line 134 def present return @representation if @representation # return nil if to_bytes.empty? in_array = [] to_hex.scan(/(.)(.)/) { |x, y| in_array += [y, x] } column_num = @width / 8 blocks = [] blocks << in_array.slice!(0, 64) until in_array.empty? out_array = [] i = 0 loop do loop do break if blocks[i % column_num].empty? out_array += blocks[i % column_num].slice!(0, 8) i += 1 end blocks.slice!(0, column_num) break if blocks.empty? end @representation = out_array end |
#rom=(p_rom) ⇒ Object
236 237 238 239 240 |
# File 'lib/sabrina/sprite.rb', line 236 def rom=(p_rom) @rom = p_rom justify @rom end |
#to_ascii(width_multiplier = 2) ⇒ String
Outputs the sprite as ASCII art with each pixel represented by the hexadecimal value of its palette index.
287 288 289 290 291 292 293 294 |
# File 'lib/sabrina/sprite.rb', line 287 def to_ascii(width_multiplier = 2) output = '' present.each_index do |i| output << present[i] * width_multiplier output << "\n" if (i + 1) % @width == 0 end output end |
#to_canvas(pal = @palette) ⇒ Canvas
Converts the internal representation to a Canvas object using the default palette or the provided one (and failing if neither is present.)
252 253 254 255 256 257 258 |
# File 'lib/sabrina/sprite.rb', line 252 def to_canvas(pal = @palette) ChunkyPNG::Canvas.from_rgb_stream( @width, present.length / @width, to_rgb(pal) ) end |
#to_png(file, dir = '', pal = @palette) ⇒ Object Also known as: to_file
Saves the internal representation to a PNG file (appending the file extension if absent) using the default palette or the provided one (and failing if neither is present.)
267 268 269 270 271 272 273 274 275 |
# File 'lib/sabrina/sprite.rb', line 267 def to_png(file, dir = '', pal = @palette) dir << '/' unless dir.empty? || dir.end_with?('/') FileUtils.mkpath(dir) unless Dir.exist?(dir) path = dir << file path << '.png' unless path.downcase.end_with?('.png') to_canvas(pal).save(path) end |
#to_rgb(pal = @palette) ⇒ String
Converts the internal representation to a stream of 0xRRGGBB
bytes using the default palette or the provided one (and failing if neither is present.)
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/sabrina/sprite.rb', line 196 def to_rgb(pal = @palette) fail 'A palette must be specified for conversion to RGB.' unless pal rgb = present.map do |x| color = pal.present[x.hex] fail "No such entry in the palette: #{x.hex}" unless color color.map(&:chr).join('') end rgb.join('') end |
#to_s ⇒ String
A blurb showing the sprite dimensions.
299 300 301 |
# File 'lib/sabrina/sprite.rb', line 299 def to_s "Sprite (#{ @width }x#{ present.length / @width })" end |