Module: RubySprites::Packer::VerticalSplit

Defined in:
lib/lash-sprites/packer/vertical_split.rb

Defined Under Namespace

Classes: Heap

Class Method Summary collapse

Class Method Details

.pack(images, options = {}) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/lash-sprites/packer/vertical_split.rb', line 8

def self.pack(images, options = {})
  width = 0
  height = 0
 
  images = images.dup

  images.sort! do |a, b|
    a.width <=> b.width
  end

  # Grab the widest image to use as a static width
  i = images.pop
  width = i.width
  height = i.height
  i.x = 0
  i.y = 0

  images.sort! do |a, b|
    a.area <=> b.area
  end

  block_heap = Heap.new {|a,b| b.area <=> a.area}

  while !images.empty?
    # This actually runs each loop, but we have the if here just in case
    if block_heap.empty?
      # There aren't any blocks to put anything in, so lets make some
      img = images.pop
      if width == 0 && height == 0
        img.x = 0
        img.y = 0
        width = img.width
        height = img.height
      else
        if img.width > width
          block_heap.insert(Block.new(width, 0, img.width - width, height))
          width = img.width
        elsif img.width < width
          block_heap.insert(Block.new(img.width, height, width - img.width, img.height))
        end
        img.x = 0
        img.y = height
        height += img.height
      end
    else
      while !block_heap.empty? && !images.empty?
        # We are looping through the blocks we have from smallest to biggest, then images smallest to biggest.
        # We find the largest image that can fit in the current block, then put it there.  If no images fit,
        # the block is thrown out.
        block = block_heap.remove
        cur_img = nil
        cur_exact = nil
        images.each_index do |i|
          cur_img = i if block.fits?(images[i])
          cur_exact = i if block.fits?(images[i]) && (block.width == images[i].width || block.height == images[i].height)
        end
        if !cur_exact.nil?
          # We prefer when one of the dimensions matches
          img = images.delete_at(cur_exact)
          img.x = block.x
          img.y = block.y
          split_block(block, img).each do |b|
            block_heap.insert(b)
          end
        elsif !cur_img.nil?
          # Best we can find
          img = images.delete_at(cur_img)
          img.x = block.x
          img.y = block.y
          split_block(block, img).each do |b|
            block_heap.insert(b)
          end
        else
          # Nothing will fit in this block, we are throwing it out
        end
      end
    end
  end
  
  return {:width => width, :height => height}
end

.split_block(block, img) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/lash-sprites/packer/vertical_split.rb', line 90

def self.split_block(block, img)
  blocks = []
  img.x = block.x
  img.y = block.y
  if (block.width - img.width) * img.height > (block.height - img.height) * img.width
    blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, block.height) if block.width != img.width
    blocks.push Block.new(block.x, block.y + img.height, img.width, block.height - img.height) if block.height != img.height
  else
    blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, img.height) if block.width != img.width
    blocks.push Block.new(block.x, block.y + img.height, block.width, block.height - img.height) if block.height != img.height
  end
  return blocks
end