forked from joejulian/gio
gpu: optimize atlas packer for smallest sizes
Previously, the packer optimized for the smalles space where the image fits. Empirically, smaller atlases can be achieved by greedily picking the smallest total area. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+46
-32
@@ -46,40 +46,54 @@ func (p *packer) newPage() {
|
||||
}
|
||||
|
||||
func (p *packer) tryAdd(s image.Point) (placement, bool) {
|
||||
// Go backwards to prioritize smaller spaces first.
|
||||
for i := len(p.spaces) - 1; i >= 0; i-- {
|
||||
space := p.spaces[i]
|
||||
var (
|
||||
bestIdx = -1
|
||||
bestSpace image.Rectangle
|
||||
bestSize = image.Pt(p.maxDim, p.maxDim)
|
||||
)
|
||||
// Go backwards to prioritize smaller spaces.
|
||||
for i, space := range p.spaces {
|
||||
rightSpace := space.Dx() - s.X
|
||||
bottomSpace := space.Dy() - s.Y
|
||||
if rightSpace >= 0 && bottomSpace >= 0 {
|
||||
// Remove space.
|
||||
p.spaces[i] = p.spaces[len(p.spaces)-1]
|
||||
p.spaces = p.spaces[:len(p.spaces)-1]
|
||||
// Put s in the top left corner and add the (at most)
|
||||
// two smaller spaces.
|
||||
pos := space.Min
|
||||
if bottomSpace > 0 {
|
||||
p.spaces = append(p.spaces, image.Rectangle{
|
||||
Min: image.Point{X: pos.X, Y: pos.Y + s.Y},
|
||||
Max: image.Point{X: space.Max.X, Y: space.Max.Y},
|
||||
})
|
||||
}
|
||||
if rightSpace > 0 {
|
||||
p.spaces = append(p.spaces, image.Rectangle{
|
||||
Min: image.Point{X: pos.X + s.X, Y: pos.Y},
|
||||
Max: image.Point{X: space.Max.X, Y: pos.Y + s.Y},
|
||||
})
|
||||
}
|
||||
idx := len(p.sizes) - 1
|
||||
size := &p.sizes[idx]
|
||||
if x := pos.X + s.X; x > size.X {
|
||||
size.X = x
|
||||
}
|
||||
if y := pos.Y + s.Y; y > size.Y {
|
||||
size.Y = y
|
||||
}
|
||||
return placement{Idx: idx, Pos: pos}, true
|
||||
if rightSpace < 0 || bottomSpace < 0 {
|
||||
continue
|
||||
}
|
||||
idx := len(p.sizes) - 1
|
||||
size := p.sizes[idx]
|
||||
if x := space.Min.X + s.X; x > size.X {
|
||||
size.X = x
|
||||
}
|
||||
if y := space.Min.Y + s.Y; y > size.Y {
|
||||
size.Y = y
|
||||
}
|
||||
if size.X*size.Y < bestSize.X*bestSize.Y {
|
||||
bestIdx = i
|
||||
bestSpace = space
|
||||
bestSize = size
|
||||
}
|
||||
}
|
||||
return placement{}, false
|
||||
if bestIdx == -1 {
|
||||
return placement{}, false
|
||||
}
|
||||
// Remove space.
|
||||
p.spaces[bestIdx] = p.spaces[len(p.spaces)-1]
|
||||
p.spaces = p.spaces[:len(p.spaces)-1]
|
||||
// Put s in the top left corner and add the (at most)
|
||||
// two smaller spaces.
|
||||
pos := bestSpace.Min
|
||||
if rem := bestSpace.Dy() - s.Y; rem > 0 {
|
||||
p.spaces = append(p.spaces, image.Rectangle{
|
||||
Min: image.Point{X: pos.X, Y: pos.Y + s.Y},
|
||||
Max: image.Point{X: bestSpace.Max.X, Y: bestSpace.Max.Y},
|
||||
})
|
||||
}
|
||||
if rem := bestSpace.Dx() - s.X; rem > 0 {
|
||||
p.spaces = append(p.spaces, image.Rectangle{
|
||||
Min: image.Point{X: pos.X + s.X, Y: pos.Y},
|
||||
Max: image.Point{X: bestSpace.Max.X, Y: pos.Y + s.Y},
|
||||
})
|
||||
}
|
||||
idx := len(p.sizes) - 1
|
||||
p.sizes[idx] = bestSize
|
||||
return placement{Idx: idx, Pos: pos}, true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user