Files
aego/asset/importers/texture/texture.go
sanspie 5eb1832907
ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
Complete Stage 12 for v0.12.0
2026-11-05 11:46:53 +03:00

158 lines
4.7 KiB
Go

package texture
import (
"bytes"
"aego/asset"
"aego/asset/pipeline"
"aego/core/errs"
"aego/core/ids"
"aego/core/log"
"aego/format/aetext"
"aego/gpu"
rtex "aego/render/texture"
)
const Version = 6
type Importer struct{}
func New() *Importer {
return &Importer{}
}
func (Importer) ID() string {
return "texture"
}
func (Importer) Version() int {
return Version
}
func (Importer) Extensions() []string {
return []string{".png"}
}
func (Importer) Defaults() pipeline.Settings { return asset.TextureDefaults() }
func filterOf(s pipeline.Settings) gpu.FilterMode {
if s.String("filter", "nearest") == "linear" {
return gpu.FilterLinear
}
return gpu.FilterNearest
}
func (i Importer) Import(ctx *pipeline.ImportContext) (*pipeline.Result, error) {
s := ctx.Meta.Settings
for _, key := range []string{"rotate", "rotation", "allow_rotation"} {
if v, ok := s[key]; ok && !((v.Kind == aetext.VBool && !v.Bool) || (v.Kind == aetext.VInt && v.Int == 0)) {
return nil, errs.New(errs.AssetImportFailed, "atlas rotation is not supported").With(log.F("path", ctx.Path), log.F("setting", key))
}
}
if s.Bool("trim", false) && s.String("atlas", "") == "" {
return nil, errs.New(errs.AssetImportFailed, "sprite trim requires an atlas group").With(log.F("path", ctx.Path))
}
semantic, err := semanticOf(ctx.Path, s)
if err != nil {
return nil, err
}
role, _ := asset.TextureRoleOf(ctx.Path, s)
srgb, err := asset.TextureSRGB(role, s)
if err != nil {
return nil, err
}
data, err := rtex.DecodePNG(bytes.NewReader(ctx.Source), srgb)
if err != nil {
return nil, errs.Wrap(err, errs.AssetImportFailed, "cannot decode the png").
With(log.F("path", ctx.Path))
}
data.NonColor = semantic != asset.TextureColor
if err := prepareSurfaceData(data, semantic, s, ctx.Meta.Subs); err != nil {
return nil, err
}
if semantic == asset.TextureHeight && s.Bool("generate_normal", false) {
semantic = asset.TextureNormal
}
data.Premultiply()
filter := filterOf(s)
links, err := surfaceBindings(ctx, data.Width, data.Height)
if err != nil {
return nil, err
}
if group := s.String("atlas", ""); group != "" && len(ctx.Meta.Subs) > 0 {
return nil, errs.New(errs.AssetImportFailed, "a sliced sheet cannot join an atlas group yet").
With(log.F("path", ctx.Path), log.F("atlas", group))
}
if group := s.String("atlas", ""); group != "" {
if s.Bool("mips", false) {
return nil, errs.New(errs.AssetImportFailed, "atlas mipmaps require per-region mip isolation; use mips=false or a standalone texture")
}
groupName := semanticName(semantic) + "/" + group
if semantic == asset.TextureEmissionRGB && !srgb {
groupName += "/linear"
}
return &pipeline.Result{
Kind: asset.ArtSpriteRegion,
Group: groupName,
Raw: data,
RawFilter: int(filter),
RawSemantic: semantic,
RawNormal: links.normal, RawPivot: ctx.Meta.Pivot, RawHasPivot: ctx.Meta.HasPivot,
RawEmission: links.emission,
Deps: links.deps,
}, nil
}
tex := asset.EncodeTexture(&asset.TextureArtifact{
Width: data.Width,
Height: data.Height,
Format: data.Format,
Filter: filter,
Mips: s.Bool("mips", false),
Semantic: semantic,
Pixels: data.Pixels,
})
region := asset.EncodeRegion(&asset.RegionArtifact{
Page: ctx.ID, Pivot: ctx.Meta.Pivot, HasPivot: ctx.Meta.HasPivot,
Normal: links.normal,
Emission: links.emission,
X: 0,
Y: 0,
W: data.Width,
H: data.Height,
PageW: data.Width,
PageH: data.Height,
Filter: filter,
})
res := &pipeline.Result{
Kind: asset.ArtTexture,
Deps: links.deps,
Artifacts: []pipeline.Produced{
{Kind: asset.ArtTexture, Data: tex},
{Kind: asset.ArtSpriteRegion, Name: ctx.ID.String() + ".aereg", Data: region},
},
}
for _, sa := range ctx.Meta.Subs {
x, y := min(max(sa.Rect[0], 0), data.Width), min(max(sa.Rect[1], 0), data.Height)
w, h := min(max(sa.Rect[2], 0), data.Width-x), min(max(sa.Rect[3], 0), data.Height-y)
if w == 0 || h == 0 {
continue
}
normalID := links.normals[sa.ID]
emissionID := links.emissions[sa.ID]
cell := asset.EncodeRegion(&asset.RegionArtifact{Page: ctx.ID, Pivot: sa.Pivot, HasPivot: sa.HasPivot, Normal: normalID, Emission: emissionID, X: x, Y: y, W: w, H: h, PageW: data.Width, PageH: data.Height, Filter: filter})
var cellDeps []ids.AssetID
if !normalID.IsZero() {
cellDeps = append(cellDeps, normalID)
}
if !emissionID.IsZero() {
cellDeps = append(cellDeps, emissionID)
}
res.Subs = append(res.Subs, pipeline.SubResult{ID: sa.ID, Name: sa.Name, Kind: asset.ArtSpriteRegion,
Deps: cellDeps,
Artifacts: []pipeline.Produced{{Kind: asset.ArtSpriteRegion, Data: cell}}})
}
return res, nil
}