mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
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:
+34
-20
@@ -46,40 +46,54 @@ func (p *packer) newPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *packer) tryAdd(s image.Point) (placement, bool) {
|
func (p *packer) tryAdd(s image.Point) (placement, bool) {
|
||||||
// Go backwards to prioritize smaller spaces first.
|
var (
|
||||||
for i := len(p.spaces) - 1; i >= 0; i-- {
|
bestIdx = -1
|
||||||
space := p.spaces[i]
|
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
|
rightSpace := space.Dx() - s.X
|
||||||
bottomSpace := space.Dy() - s.Y
|
bottomSpace := space.Dy() - s.Y
|
||||||
if rightSpace >= 0 && bottomSpace >= 0 {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bestIdx == -1 {
|
||||||
|
return placement{}, false
|
||||||
|
}
|
||||||
// Remove space.
|
// Remove space.
|
||||||
p.spaces[i] = p.spaces[len(p.spaces)-1]
|
p.spaces[bestIdx] = p.spaces[len(p.spaces)-1]
|
||||||
p.spaces = 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)
|
// Put s in the top left corner and add the (at most)
|
||||||
// two smaller spaces.
|
// two smaller spaces.
|
||||||
pos := space.Min
|
pos := bestSpace.Min
|
||||||
if bottomSpace > 0 {
|
if rem := bestSpace.Dy() - s.Y; rem > 0 {
|
||||||
p.spaces = append(p.spaces, image.Rectangle{
|
p.spaces = append(p.spaces, image.Rectangle{
|
||||||
Min: image.Point{X: pos.X, Y: pos.Y + s.Y},
|
Min: image.Point{X: pos.X, Y: pos.Y + s.Y},
|
||||||
Max: image.Point{X: space.Max.X, Y: space.Max.Y},
|
Max: image.Point{X: bestSpace.Max.X, Y: bestSpace.Max.Y},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if rightSpace > 0 {
|
if rem := bestSpace.Dx() - s.X; rem > 0 {
|
||||||
p.spaces = append(p.spaces, image.Rectangle{
|
p.spaces = append(p.spaces, image.Rectangle{
|
||||||
Min: image.Point{X: pos.X + s.X, Y: pos.Y},
|
Min: image.Point{X: pos.X + s.X, Y: pos.Y},
|
||||||
Max: image.Point{X: space.Max.X, Y: pos.Y + s.Y},
|
Max: image.Point{X: bestSpace.Max.X, Y: pos.Y + s.Y},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
idx := len(p.sizes) - 1
|
idx := len(p.sizes) - 1
|
||||||
size := &p.sizes[idx]
|
p.sizes[idx] = bestSize
|
||||||
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
|
return placement{Idx: idx, Pos: pos}, true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return placement{}, false
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user