openquell/assets/loader-sprites.go

138 lines
3.1 KiB
Go

package assets
import (
"bytes"
"embed"
"encoding/json"
"image"
_ "image/png"
"log"
"log/slog"
"path"
"strings"
"github.com/alecthomas/repr"
"github.com/hajimehoshi/ebiten/v2"
)
// Maps image name to image data
type AssetRegistry map[string]*ebiten.Image
type AnimationGeo struct {
X int `json:"x"`
Y int `json:"y"`
Width int `json:"w"`
Height int `json:"h"`
}
type AnimationFrame struct {
Position AnimationGeo `json:"frame"`
// FIXME: maybe also add delay etc? might be cool to tweak these things from LDTK
}
type AnimationMeta struct {
Name string `json:"image"`
Geo AnimationGeo `json:"size"`
}
// Needed to thaw sprite set written by asesprite
type AnimationJSON struct {
Meta AnimationMeta `json:"Meta"`
Frames []AnimationFrame `json:"frames"`
}
// Animation data
type AnimationSet struct {
Width, Height int
Sprites []*ebiten.Image
File string
}
type AnimationRegistry map[string]AnimationSet
//go:embed sprites/*.png fonts/*.ttf levels/*.ldtk shaders/*.kg sprites/*.json
var assetfs embed.FS
var Assets, Animations = LoadImages()
func LoadImages() (AssetRegistry, AnimationRegistry) {
dir := "sprites"
images := AssetRegistry{}
rawanimations := []AnimationJSON{}
animations := AnimationRegistry{}
// we use embed.FS to iterate over all files in ./assets/
entries, err := assetfs.ReadDir(dir)
if err != nil {
log.Fatalf("failed to read assets dir %s: %s", dir, err)
}
for _, imagefile := range entries {
path := path.Join(dir, imagefile.Name())
switch {
case strings.HasSuffix(path, ".png"):
fd, err := assetfs.Open(path)
if err != nil {
log.Fatalf("failed to open image file %s: %s", imagefile.Name(), err)
}
defer fd.Close()
name := strings.TrimSuffix(imagefile.Name(), ".png")
img, _, err := image.Decode(fd)
if err != nil {
log.Fatalf("failed to decode image %s: %s", imagefile.Name(), err)
}
images[name] = ebiten.NewImageFromImage(img)
slog.Debug("loaded asset", "path", path)
case strings.HasSuffix(path, ".json"):
fd, err := assetfs.Open(path)
if err != nil {
log.Fatalf("failed to open json file %s: %s", imagefile.Name(), err)
}
defer fd.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(fd)
animationjson := AnimationJSON{}
err = json.Unmarshal(buf.Bytes(), &animationjson)
if err != nil {
log.Fatalf("failed to parse JSON: %s", err)
}
rawanimations = append(rawanimations, animationjson)
}
}
// preprocess animation sprites
for _, animation := range rawanimations {
animationset := AnimationSet{}
animationset.File = strings.TrimSuffix(animation.Meta.Name, ".png")
animationset.Width = animation.Meta.Geo.Width
animationset.Height = animation.Meta.Geo.Height
for _, frame := range animation.Frames {
sprite := images[animationset.File].SubImage(
image.Rect(
frame.Position.X,
frame.Position.Y,
frame.Position.Width,
frame.Position.Height,
)).(*ebiten.Image)
animationset.Sprites = append(animationset.Sprites, sprite)
}
animations[animationset.File] = animationset
}
repr.Println(animations)
return images, animations
}