require_relative 'common' options = get_options(__FILE__) sprite_path = options['sprite_path'] csv_path = options['generate_config_path'] atlas_path = options['generate_atlas_path'] padding = options['padding_size'] recreate_dir atlas_path ensure_dir csv_path # $ gem install chunky_png # $ gem install binpack require 'chunky_png' require 'binpack' require 'csv' Point = Struct.new(:x, :y) Box = Struct.new(:top_left, :bottom_right) csv_atlas = CSV.open("#{csv_path}/atlas.csv", 'wb') csv_atlas << ['Id', 'Path'] csv_atlas << ['', ''] csv_atlas << [':id', ':path'] csv_sprite = CSV.open("#{csv_path}/sprite.csv", 'wb') csv_sprite << ['Id', 'AtlasId', 'X', 'Y'] csv_sprite << ['', '', '', ''] csv_sprite << [':id', '@atlas', ':int', ':int'] Dir["#{sprite_path}/*"].each do |path| atlas_name = convert_case(File::basename(path)) next unless File::directory?(path) atlas_size = 32 bins = [] loop do bins.clear begin sprites = Dir["#{path}/*"].collect do |file| sprite = ChunkyPNG::Image.from_file(file) sprite.define_singleton_method :file do return file end sprite end items = sprites.collect { |sprite| Binpack::Item.new(sprite, sprite.width, sprite.height) } bins = Binpack::Bin.pack(items, [], Binpack::Bin.new(atlas_size, atlas_size, padding)) raise 'too small' if bins.size > 1 break rescue atlas_size *= 2 break if atlas_size >= 2048 end end bins.each do |bin| atlas = ChunkyPNG::Image.new(atlas_size, atlas_size, ChunkyPNG::Color::TRANSPARENT) bin.items.each do |item| unit, x, y = *item puts "#{x}, #{y}" atlas.compose!(unit.obj, x, y) csv_sprite << [convert_case(File.basename(unit.obj.file, '.png')), atlas_name, x, y] end atlas_file = "#{atlas_path}/#{File::basename(path)}.png" atlas.save atlas_file csv_atlas << [atlas_name, File.basename(atlas_file)] end end