147 lines
2.5 KiB
Go
147 lines
2.5 KiB
Go
package assetstore
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"log"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
|
|
"code.ur.gs/lupine/ordoor/internal/data"
|
|
)
|
|
|
|
type Object struct {
|
|
assets *AssetStore
|
|
sprites []*Sprite
|
|
|
|
raw *data.Object
|
|
NumSprites int
|
|
Name string
|
|
}
|
|
|
|
type Sprite struct {
|
|
obj *Object
|
|
|
|
XOffset int // TODO: replace these everywhere with Rect
|
|
YOffset int
|
|
Width int
|
|
Height int
|
|
|
|
ID string
|
|
Rect image.Rectangle
|
|
Image *ebiten.Image
|
|
}
|
|
|
|
func (a *AssetStore) Object(name string) (*Object, error) {
|
|
name = canonical(name)
|
|
|
|
if obj, ok := a.objs[name]; ok {
|
|
return obj, nil
|
|
}
|
|
log.Printf("Loading object %v", name)
|
|
|
|
filename, err := a.lookup(name, "obj", "Obj")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obj, err := a.ObjectByPath(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
a.objs[name] = obj
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
// FIXME: Objects loaded by path are not cached
|
|
func (a *AssetStore) ObjectByPath(path string) (*Object, error) {
|
|
name := filepath.Base(path)
|
|
name = strings.Replace(name, filepath.Ext(name), "", -1)
|
|
name = canonical(name)
|
|
|
|
raw, err := data.LoadObjectLazily(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obj := &Object{
|
|
assets: a,
|
|
sprites: make([]*Sprite, int(raw.NumSprites)),
|
|
raw: raw,
|
|
NumSprites: int(raw.NumSprites),
|
|
Name: canonical(name),
|
|
}
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
// Loads all sprites in the object eagerly
|
|
func (o *Object) LoadSprites() error {
|
|
for i := 0; i < o.NumSprites; i++ {
|
|
if _, err := o.Sprite(i); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (o *Object) Sprites(start, count int) ([]*Sprite, error) {
|
|
out := make([]*Sprite, count)
|
|
|
|
for i := start; i < start+count; i++ {
|
|
sprite, err := o.Sprite(i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out[i-start] = sprite
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (o *Object) Sprite(idx int) (*Sprite, error) {
|
|
if sprite := o.sprites[idx]; sprite != nil {
|
|
return sprite, nil
|
|
}
|
|
|
|
if o.raw.Sprites[idx] == nil {
|
|
if err := o.raw.LoadSprite(idx); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
raw := o.raw.Sprites[idx]
|
|
img, err := ebiten.NewImageFromImage(raw.ToImage(), ebiten.FilterDefault)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rect := image.Rect(
|
|
int(raw.XOffset),
|
|
int(raw.YOffset),
|
|
int(raw.XOffset+raw.Width),
|
|
int(raw.YOffset+raw.Height),
|
|
)
|
|
|
|
sprite := &Sprite{
|
|
ID: fmt.Sprintf("%v:%v", o.raw.Name, idx),
|
|
obj: o,
|
|
Width: rect.Dx(),
|
|
Height: rect.Dy(),
|
|
XOffset: rect.Min.X,
|
|
YOffset: rect.Min.Y,
|
|
Rect: rect,
|
|
Image: img,
|
|
}
|
|
|
|
o.sprites[idx] = sprite
|
|
|
|
return sprite, nil
|
|
}
|