This cuts memory use significantly, since many sprites in an object are never used. We can get savings over time by evicting sprites when they go out of scope, but that's, well, out of scope. To achieve this, I introduce an assetstore package that is in charge of loading things from the filesystem. This also allows some lingering case-sensitivity issues to be handled cleanly. I'd hoped that creating fewer ebiten.Image instances would help CPU usage, but that doesn't seem to be the case.
65 lines
1.1 KiB
Go
65 lines
1.1 KiB
Go
package assetstore
|
|
|
|
import (
|
|
"github.com/hajimehoshi/ebiten"
|
|
|
|
"code.ur.gs/lupine/ordoor/internal/data"
|
|
)
|
|
|
|
type Object struct {
|
|
assets *AssetStore
|
|
images []*ebiten.Image
|
|
|
|
raw *data.Object
|
|
}
|
|
|
|
func (a *AssetStore) Object(name string) (*Object, error) {
|
|
name = canonical(name)
|
|
|
|
if obj, ok := a.objs[name]; ok {
|
|
return obj, nil
|
|
}
|
|
|
|
filename, err := a.lookup(name, "obj", "Obj")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
raw, err := data.LoadObjectLazily(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obj := &Object{
|
|
assets: a,
|
|
images: make([]*ebiten.Image, int(raw.NumSprites)),
|
|
raw: raw,
|
|
}
|
|
a.objs[name] = obj
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
// Filled lazily
|
|
func (o *Object) Image(idx int) (*ebiten.Image, error) {
|
|
if img := o.images[idx]; img != nil {
|
|
return img, nil
|
|
}
|
|
|
|
if o.raw.Sprites[idx] == nil {
|
|
if err := o.raw.LoadSprite(idx); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
stdImg := o.raw.Sprites[idx].ToImage()
|
|
img, err := ebiten.NewImageFromImage(stdImg, ebiten.FilterDefault)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
o.images[idx] = img
|
|
|
|
return img, nil
|
|
}
|