2021-08-26 11:33:58 +10:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/gob"
|
|
|
|
"image"
|
|
|
|
"io/fs"
|
|
|
|
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
imageCache = make(map[assetKey]*ebiten.Image)
|
|
|
|
|
|
|
|
// Ensure types satisfy interfaces.
|
|
|
|
_ Loader = &ImageRef{}
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2021-09-03 09:13:12 +10:00
|
|
|
gob.Register(&ImageRef{})
|
2021-08-26 11:33:58 +10:00
|
|
|
}
|
|
|
|
|
2021-08-26 11:35:15 +10:00
|
|
|
// ImageRef loads images from the AssetFS into *ebiten.Image form. It is your
|
|
|
|
// responsibility to import _ "image/..." for whatever format the files are in,
|
|
|
|
// and to load it (either return it as a subcomponent from Scan so that Game
|
|
|
|
// will Load it, or call Load yourself).
|
2021-08-26 11:33:58 +10:00
|
|
|
type ImageRef struct {
|
|
|
|
Path string
|
|
|
|
|
|
|
|
image *ebiten.Image
|
|
|
|
}
|
|
|
|
|
2021-08-26 11:35:15 +10:00
|
|
|
// Image returns the image, or nil if not loaded. Multiple distinct ImageRefs
|
|
|
|
// can use the same path efficiently.
|
2021-08-26 11:33:58 +10:00
|
|
|
func (r *ImageRef) Image() *ebiten.Image {
|
|
|
|
return r.image
|
|
|
|
}
|
|
|
|
|
2021-08-26 11:35:15 +10:00
|
|
|
// Load loads the image. Load is required before Image returns. Loading the same
|
|
|
|
// path multiple times uses a cache to return the same image.
|
2021-08-26 11:33:58 +10:00
|
|
|
func (r *ImageRef) Load(assets fs.FS) error {
|
|
|
|
// Fast path load from cache
|
|
|
|
r.image = imageCache[assetKey{assets, r.Path}]
|
|
|
|
if r.image != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Slow path
|
|
|
|
f, err := assets.Open(r.Path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
i, _, err := image.Decode(f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.image = ebiten.NewImageFromImage(i)
|
|
|
|
imageCache[assetKey{assets, r.Path}] = r.image
|
|
|
|
return nil
|
|
|
|
}
|