class AuthorEngine::SpriteEditor

Constants

BLANK_COLOR

Public Instance Methods

button_down(id) click to toggle source
Calls superclass method AuthorEngine::View#button_down
# File lib/author_engine/views/sprite_editor.rb, line 312
def button_down(id)
  super

  copy_sprite  if window.control_button_down? && id == Gosu::KbC
  paste_sprite if window.control_button_down? && id == Gosu::KbV
end
button_up(id) click to toggle source
Calls superclass method AuthorEngine::View#button_up
# File lib/author_engine/views/sprite_editor.rb, line 319
def button_up(id)
  super
  @palette.button_up(id)
  @sprites_picker.button_up(id)

  @tools.each{ |b| b.button_up(id) }

  if @pixel_floodfill
    pixel = get_pixel_at(window.mouse_x, window.mouse_y)
    if pixel
      floodfill(pixel, pixel.color, @palette.color) if id == Gosu::MsLeft if @palette.color
      floodfill(pixel, pixel.color, BLANK_COLOR) if id == Gosu::MsRight
    end
  end

  update_sprite if (id == Gosu::MsLeft || id == Gosu::MsRight) && @canvas_changed
end
copy_sprite() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 270
def copy_sprite
  @copied_pixels = []
  @pixels.each {|pixel| @copied_pixels << pixel.dup}
end
create_grid(x, y, size) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 117
def create_grid(x, y, size)
  size = size * window.square_scale

  @grid_x = (window.width / 2) - (((size * x) / 2) + size*2 )
  @grid_y = window.container.header_height + size
  @grid_width = x * size
  @grid_height = y * size
  @grid_pixel_size = size
  @grid_columns = x
  @grid_rows    = y

  y.times do |_y|
    x.times do |_x|
      @pixels << Pixel.new(
        @grid_x+(_x*size), @grid_y+(_y*size),
        size, size,
        BLANK_COLOR
      )
    end
  end
end
draw() click to toggle source
Calls superclass method AuthorEngine::View#draw
# File lib/author_engine/views/sprite_editor.rb, line 75
def draw
  super
  @pixels.each(&:draw)
  highlight_pixel
  @coordinates.draw

  Gosu.draw_rect(@grid_x-window.square_scale, @grid_y-window.square_scale, @grid_width+(window.square_scale*2), @grid_height+(window.square_scale*2), Gosu::Color::WHITE)
  Gosu.draw_rect(@grid_x, @grid_y, @grid_width, @grid_height, Gosu::Color.rgba(10, 10, 10, 200))
  @palette.draw
  @sprites_picker.draw

  @tools.each(&:draw)

  Gosu.clip_to(@grid_x, @grid_y, @grid_width, @grid_height) do
    if @pixel_floodfill
      @bucket_icon.draw(window.mouse_x, window.mouse_y - (@bucket_icon.width * @scale), 1000, @scale, @scale)
    else
      @pencil_icon.draw(window.mouse_x, window.mouse_y - (@pencil_icon.width * @scale), 1000, @scale, @scale)
    end
  end
end
erase() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 170
def erase
  paint(BLANK_COLOR)
end
floodfill(pixel, target_color, replacement_color) click to toggle source

AKA The Bucket Tool @param pixel [Pixel] @param target_color [Gosu::Color] color to search and replace with replacement_color @param replacement_color [Gosu::Color] color to replace Pixel's current color

# File lib/author_engine/views/sprite_editor.rb, line 195
def floodfill(pixel, target_color, replacement_color)
  return unless pixel
  return if pixel.color == replacement_color
  return if pixel.color != target_color
  return if target_color != BLANK_COLOR && @pixel_lock # don't replace non-blank pixels with color if pixels are locked

  pixel.color = replacement_color
  @canvas_changed = true

  # UP
  _pixel = get_pixel_at(pixel.x, pixel.y - @grid_pixel_size)
  floodfill(_pixel, target_color, replacement_color)

  # DOWN
  _pixel = get_pixel_at(pixel.x, pixel.y + @grid_pixel_size)
  floodfill(_pixel, target_color, replacement_color)

  # LEFT
  _pixel = get_pixel_at(pixel.x - @grid_pixel_size, pixel.y)
  floodfill(_pixel, target_color, replacement_color)

  # RIGHT
  _pixel = get_pixel_at(pixel.x + @grid_pixel_size, pixel.y)
  floodfill(_pixel, target_color, replacement_color)
end
focus() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 70
def focus
  window.show_cursor = true
  window.caption = "Sprite Editor"
end
get_pixel_at(x, y) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 174
def get_pixel_at(x, y)
  return if (x >= @grid_x+@grid_width || y >= @grid_y+@grid_height)
  x = normalize_x(x)
  y = normalize_y(y)
  return if (x < 0 || y < 0)

  @pixels[(x + (@grid_columns * y))]
end
highlight_pixel() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 139
def highlight_pixel
  return unless @palette.color

  pixel = get_pixel_at(window.mouse_x, window.mouse_y)
  return unless pixel
  Gosu.draw_rect(
    pixel.x, pixel.y,
    pixel.width, pixel.height,
    @palette.color,
    6
  )

  Gosu.draw_rect(
    pixel.x, pixel.y,
    pixel.width, pixel.height,
    Gosu::Color.rgba(255,255,255, 100),
    6
  )
end
import_spritesheet(data) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 300
def import_spritesheet(data)
  return if data.to_blob.size < 4
  sprites = Gosu::Image.load_tiles(data, 16, 16, retro: true, tileable: true)
  @sprites.clear

  sprites.each do |sprite|
    @sprites.push(sprite)
  end

  set_sprite
end
normalize_x(int) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 183
def normalize_x(int)
  return ((int - @grid_x) / @grid_pixel_size).floor
end
normalize_y(int) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 187
def normalize_y(int)
  return ((int - @grid_y) / @grid_pixel_size).floor
end
paint(color = @palette.color) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 159
def paint(color = @palette.color)
  pixel = get_pixel_at(window.mouse_x, window.mouse_y)

  return unless pixel
  return if color.nil?
  return if pixel.color != BLANK_COLOR && @pixel_lock

  pixel.color = color
  @canvas_changed = true
end
paste_sprite() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 275
def paste_sprite
  if @copied_pixels
    @pixels.each_with_index do |pixel, i|
      pixel.color = @copied_pixels[i].color
    end
    @canvas_changed = true
    update_sprite
  end

  @copied_pixels = nil
end
set_sprite() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 225
def set_sprite
  if @sprites[@sprites_picker.active_sprite]
    sprite_pixels(@sprites[@sprites_picker.active_sprite])
  else
    @pixels.each do |pixel|
      pixel.color = BLANK_COLOR
    end
  end
end
setup() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 20
def setup
  @pixels = []
  @active_color = Gosu::Color.rgba(101,1,101, 255)

  create_grid(16, 16, 4)
  @canvas_changed = false
  @scale = 1 * window.square_scale
  @palette = Palette.new(x: @grid_x + @grid_width + @grid_pixel_size, y: @grid_y)
  @sprites_picker = SpritePicker.new(y: @grid_y + @grid_height + (@grid_pixel_size * 2))
  @coordinates    = Text.new(message: "1:1", x: @scale, y: @grid_y)

  @sprites= Array.new(@sprites_picker.rows*@sprites_picker.columns, nil)

  @tools = []
  @pixel_lock = false
  @pixel_floodfill = false # aka bucket tool

  @tools << Button.new(image: "assets/ui/unlock_icon.png", tooltip: "Toggle pixel lock", x: @palette.x, y: @palette.y + @palette.height + (window.square_scale * 2), color: dark_purple) do |b|
    @unlock_icon ||= b.image
    @lock_icon ||= AuthorEngine::Image.new("assets/ui/lock_icon.png", retro: true)

    @pixel_lock = !@pixel_lock

    if @pixel_lock
      b.image = @lock_icon
    else
      b.image = @unlock_icon
    end
  end

  @pencil_icon = AuthorEngine::Image.new("assets/ui/pencil_icon.png", retro: true)
  @bucket_icon = AuthorEngine::Image.new("assets/ui/bucket_icon.png", retro: true)

  @tools << Button.new(image: @pencil_icon, tooltip: "Toggle pencil/bucket", x: @palette.x + @tools.first.width + 1, y: @palette.y + @palette.height + (window.square_scale * 2), color: dark_purple) do |b|
    @pixel_floodfill = !@pixel_floodfill

    if @pixel_floodfill
      b.image = @bucket_icon
    else
      b.image = @pencil_icon
    end
  end

  if window.container.savefile.sprites.to_blob.length < 4
    import_spritesheet(spritesheet)
  else
    import_spritesheet(window.container.savefile.sprites)
  end
end
sprite_pixels(image) click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 235
def sprite_pixels(image)
  pixels = []
  image.to_blob.bytes.to_a.each_slice(4).each_with_index do |pixel|
    buffer = []
    pixel.each do |chunk|
      buffer << Integer(chunk)
    end
    pixels << buffer
  end

  pixels.each_with_index do |pixel, index|
    @pixels[index].color = Gosu::Color.rgba(pixel[0], pixel[1], pixel[2], pixel[3])
  end
end
sprites() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 221
def sprites
  @sprites
end
spritesheet() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 287
def spritesheet
  sheet = Gosu.render(512, 128, retro: true) do
    @sprites.each_slice(512/16).each_with_index do |row, y|
      row.each_with_index do |sprite, x|
        next if sprite.nil?
        sprite.draw(x * 16, y * 16, 0)
      end
    end
  end

  return sheet
end
update() click to toggle source
Calls superclass method AuthorEngine::View#update
# File lib/author_engine/views/sprite_editor.rb, line 97
def update
  super
  unless @pixel_floodfill
    paint if Gosu.button_down?(Gosu::MsLeft)
    erase if Gosu.button_down?(Gosu::MsRight)
  end
  @palette.update

  update_coordinates
end
update_coordinates() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 108
def update_coordinates
  x = normalize_x(window.mouse_x)
  y = normalize_y(window.mouse_y)
  return if (x >= @grid_columns || y >= @grid_rows)
  return if (x < 0 || y < 0)

  @coordinates.message = "#{x+1}:#{y+1}"
end
update_sprite() click to toggle source
# File lib/author_engine/views/sprite_editor.rb, line 250
def update_sprite
  list = []

  @pixels.each_slice(window.sprite_size).each do |row|
    list << row
  end

  image = Gosu.render(window.sprite_size, window.sprite_size, retro: true) do
    list.each_with_index do |row, y|
      row.each_with_index do |pixel, x|
        Gosu.draw_rect(x, y, 1, 1, pixel.color)
      end
    end
  end

  @sprites[@sprites_picker.active_sprite] = nil # release image for garbage collection?
  @sprites[@sprites_picker.active_sprite] = image
  @canvas_changed = false
end