ImageRef implements Loader

This commit is contained in:
Josh Deprez 2021-08-20 17:05:47 +10:00
parent af89c01dbd
commit 245d939f2c
4 changed files with 33 additions and 12 deletions

View file

@ -20,7 +20,8 @@ var (
imageCache = make(map[string]*ebiten.Image) imageCache = make(map[string]*ebiten.Image)
// Ensure SceneRef does the same stuff as Scene. // Ensure ref types satisfy interfaces.
_ Loader = &ImageRef{}
_ Scener = &SceneRef{} _ Scener = &SceneRef{}
) )
@ -52,36 +53,43 @@ func (r *AnimRef) Anim() *Anim {
// ImageRef loads images from the AssetFS into *ebiten.Image form. // ImageRef loads images from the AssetFS into *ebiten.Image form.
// It is your responsibility to import _ "image/..." for whatever // It is your responsibility to import _ "image/..." for whatever
// format the files are in. // 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).
type ImageRef struct { type ImageRef struct {
Path string Path string
image *ebiten.Image image *ebiten.Image
} }
// Image returns the image. If it hasn't been loaded yet, it loads. // Image returns the image, or nil if not loaded.
// Multiple distinct ImageRefs can use the same path. // Multiple distinct ImageRefs can use the same path.
// TODO: adopt Loader?
func (r *ImageRef) Image() *ebiten.Image { func (r *ImageRef) Image() *ebiten.Image {
if r.image != nil { return r.image
return r.image }
}
// Load loads the image. Load is required before Image returns.
// Loading the same path multiple times uses a cache to return
// the same image.
func (r *ImageRef) Load() error {
// Fast path load from cache
r.image = imageCache[r.Path] r.image = imageCache[r.Path]
if r.image != nil { if r.image != nil {
return r.image return nil
} }
// Slow path
f, err := AssetFS.Open(r.Path) f, err := AssetFS.Open(r.Path)
if err != nil { if err != nil {
log.Fatalf("Couldn't open asset: %v", err) return err
} }
defer f.Close() defer f.Close()
i, _, err := image.Decode(f) i, _, err := image.Decode(f)
if err != nil { if err != nil {
log.Fatalf("Couldn't decode asset: %v", err) return err
} }
r.image = ebiten.NewImageFromImage(i) r.image = ebiten.NewImageFromImage(i)
imageCache[r.Path] = r.image imageCache[r.Path] = r.image
return r.image return nil
} }
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS. // SceneRef loads a gzipped, gob-encoded Scene from the asset FS.

View file

@ -13,6 +13,7 @@ var (
_ Drawer = &Image{} _ Drawer = &Image{}
_ DrawOrderer = &Image{} _ DrawOrderer = &Image{}
_ ParallaxScaler = &Image{} _ ParallaxScaler = &Image{}
_ Scanner = &Image{}
) )
func init() { func init() {
@ -36,3 +37,6 @@ func (i *Image) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
opts.GeoM = geom opts.GeoM = geom
screen.DrawImage(i.Src.Image(), &opts) screen.DrawImage(i.Src.Image(), &opts)
} }
// Scan returns a slice containing Src.
func (i *Image) Scan() []interface{} { return []interface{}{&i.Src} }

View file

@ -51,7 +51,12 @@ func (s *Sprite) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
screen.DrawImage(src.SubImage(image.Rectangle{sp, sp.Add(s.FrameSize)}).(*ebiten.Image), &opts) screen.DrawImage(src.SubImage(image.Rectangle{sp, sp.Add(s.FrameSize)}).(*ebiten.Image), &opts)
} }
func (s *Sprite) Scan() []interface{} { return []interface{}{&s.Actor} } func (s *Sprite) Scan() []interface{} {
return []interface{}{
&s.Actor,
&s.Src,
}
}
func (s *Sprite) SetAnim(a *Anim) { func (s *Sprite) SetAnim(a *Anim) {
if s.anim != a { if s.anim != a {

View file

@ -13,6 +13,7 @@ var (
_ Collider = &Tilemap{} _ Collider = &Tilemap{}
_ Drawer = &Tilemap{} _ Drawer = &Tilemap{}
_ DrawOrderer = &Tilemap{} _ DrawOrderer = &Tilemap{}
_ Scanner = &Tilemap{}
_ Updater = &Tilemap{} _ Updater = &Tilemap{}
) )
@ -86,6 +87,9 @@ func (t *Tilemap) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
} }
} }
// Scan returns a slice containing Src.
func (t *Tilemap) Scan() []interface{} { return []interface{}{&t.Src} }
// Update calls Update on any tiles that are Updaters, e.g. AnimatedTile. // Update calls Update on any tiles that are Updaters, e.g. AnimatedTile.
func (t *Tilemap) Update() error { func (t *Tilemap) Update() error {
if t.Disabled { if t.Disabled {