292 lines
7.7 KiB
Go
292 lines
7.7 KiB
Go
package gpupreview
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"image"
|
|
"testing"
|
|
|
|
"aego/art"
|
|
"aego/asset"
|
|
"aego/core/mathx"
|
|
"aego/modules/particles"
|
|
"aego/modules/render2d"
|
|
"aego/scene"
|
|
"aego/schema"
|
|
)
|
|
|
|
func TestFrameSpecificPivotWinsOverLaterDefault(t *testing.T) {
|
|
d, err := art.New(4, 4, art.RGBA, art.Limits{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
f := d.Info().Frames[0].ID
|
|
e, err := d.Begin(d.Revision(), "pivots")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, s := range []art.Slice{
|
|
{Name: "pivot", Frame: f, Rect: image.Rect(0, 0, 4, 4), Pivot: image.Pt(1, 3)},
|
|
{Name: "pivot", Rect: image.Rect(0, 0, 4, 4), Pivot: image.Pt(2, 2)},
|
|
} {
|
|
if _, err = e.SetSlice(s); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
change, err := e.Prepare()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = change.Apply(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
data, err := d.Encode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a, err := New(true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer a.Close()
|
|
if err = a.Publish(1, d.Revision(), data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sr, _ := scene.Get[render2d.SpriteRenderer](a.sc, a.sprite)
|
|
if want := mathx.V2(.25, .75); sr.Origin != want {
|
|
t.Fatalf("preview origin %v differs from frame pivot %v", sr.Origin, want)
|
|
}
|
|
// A presentation option change must preserve the same canonical pivot.
|
|
o := DefaultOptions()
|
|
o.FlipX = true
|
|
o.Shadows = true
|
|
o.Mode = "lit"
|
|
if err = a.Configure(o); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if sr.Origin != mathx.V2(.25, .75) {
|
|
t.Fatal("reconfiguration lost the frame pivot")
|
|
}
|
|
}
|
|
|
|
func fixture(t *testing.T) (*art.Document, []byte) {
|
|
t.Helper()
|
|
d, e := art.New(16, 16, art.RGBA, art.Limits{})
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
t.Cleanup(d.Close)
|
|
x, e := d.Begin(d.Revision(), "fixture")
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if e = x.SetPixel(d.Info().Cels[0].ID, 5, 6, art.Paint{Color: art.Color{R: 255, G: 96, B: 32, A: 128}}, nil, false); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
c, e := x.Prepare()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if e = c.Apply(); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
b, e := d.Encode()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
return d, b
|
|
}
|
|
|
|
func TestPreviewUsesRuntimeWorldAndNeverMutatesAuthoringDocument(t *testing.T) {
|
|
d, b := fixture(t)
|
|
a, e := New(true)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
defer a.Close()
|
|
if e = a.Publish(1, d.Revision(), b); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
a.Step()
|
|
}
|
|
if a.Status().State != "ready" {
|
|
t.Fatalf("preview not ready: %+v", a.Status())
|
|
}
|
|
if e = a.Publish(1, d.Revision(), b); !errors.Is(e, art.ErrConflict) {
|
|
t.Fatalf("stale publish: %v", e)
|
|
}
|
|
o := DefaultOptions()
|
|
o.Mode = "particles"
|
|
if e = a.Configure(o); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
for i := 0; i < 30; i++ {
|
|
a.Step()
|
|
}
|
|
p := particles.Of(a.world)
|
|
if p == nil || p.Stats().Alive == 0 {
|
|
t.Fatalf("real ParticleSystem2D did not simulate: %+v", a.Status())
|
|
}
|
|
pc, ok := scene.Get[particles.ParticleSystem2D](a.sc, a.emitter)
|
|
if !ok || len(pc.Frames) != 1 {
|
|
t.Fatal("flipbook not assigned")
|
|
}
|
|
o.Mode = "lit"
|
|
o.Bloom = true
|
|
o.Shadows = true
|
|
o.FlipX = true
|
|
if e = a.Configure(o); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
a.Step()
|
|
}
|
|
sr, _ := scene.Get[render2d.SpriteRenderer](a.sc, a.sprite)
|
|
if !sr.FlipX {
|
|
t.Fatal("preview flip not applied")
|
|
}
|
|
post, _ := scene.Get[render2d.PostProcess](a.sc, a.camera)
|
|
if !post.Enabled || len(post.Effects) != 1 {
|
|
t.Fatal("runtime Bloom not configured")
|
|
}
|
|
after, e := d.Encode()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if !bytes.Equal(after, b) {
|
|
t.Fatal("preview mutated authoring state")
|
|
}
|
|
}
|
|
|
|
func TestInvalidSnapshotAndMissingChannelDoNotPublishOldPixels(t *testing.T) {
|
|
d, b := fixture(t)
|
|
a, e := New(true)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
defer a.Close()
|
|
if e = a.Publish(1, d.Revision(), b); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if e = a.Publish(2, d.Revision(), []byte("bad")); e == nil {
|
|
t.Fatal("invalid snapshot accepted")
|
|
}
|
|
if a.Status().Sequence != 1 {
|
|
t.Fatal("failed publication changed generation")
|
|
}
|
|
o := DefaultOptions()
|
|
o.Mode = "normal"
|
|
if e = a.Configure(o); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if a.Status().Error == "" {
|
|
t.Fatal("missing normal channel not diagnosed")
|
|
}
|
|
o.Mode = "sprite"
|
|
if e = a.Configure(o); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if a.Status().Error != "" {
|
|
t.Fatal("diagnostic survived corrected mode")
|
|
}
|
|
}
|
|
|
|
func TestLitEmissionBelongsToArtworkAndCurrentFrame(t *testing.T) {
|
|
d, _ := fixture(t)
|
|
i := d.Info()
|
|
first, layer := i.Frames[0].ID, i.Layers[0].ID
|
|
e, err := d.Begin(d.Revision(), "emissive and albedo-only frames")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
emission, err := e.EnsureCel(layer, first, art.Emission)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = e.SetPixel(emission, 5, 6, art.Paint{Color: art.Color{R: 255, G: 160, B: 32, A: 255}}, nil, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := e.AddFrame(first, 100)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = e.CopyCel(i.Cels[0].ID, layer, second, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c, err := e.Prepare()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = c.Apply(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
before, err := d.Encode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a, err := New(true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer a.Close()
|
|
if err = a.Publish(1, d.Revision(), before); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base, ok := a.loader.Material(asset.BuiltinMaterialLit)
|
|
if !ok {
|
|
t.Fatal("stock Lit material missing")
|
|
}
|
|
baseColor, _ := base.Get("EmissionColor")
|
|
baseIntensity, _ := base.Get("EmissionIntensity")
|
|
baseGeneration := base.Generation()
|
|
if baseColor != [4]float32{0, 0, 0, 1} || baseIntensity != [4]float32{} {
|
|
t.Fatal("unexpected stock emission defaults", baseColor, baseIntensity)
|
|
}
|
|
o := DefaultOptions()
|
|
o.Shadows, o.Emission = true, 16
|
|
for _, mode := range []string{"lit", "flash", "lit", "dissolve", "sprite", "lit"} {
|
|
for _, f := range []art.ID{first, second, first} {
|
|
o.Mode, o.Frame = mode, f
|
|
if err = a.Configure(o); err != nil {
|
|
t.Fatal(mode, f, err)
|
|
}
|
|
if mode == "lit" {
|
|
color, err := render2d.GetMaterialParameter(a.sc, a.sprite, "EmissionColor")
|
|
if err != nil || color.Kind != schema.KindColor || color.C != (mathx.Color{R: 1, G: 1, B: 1, A: 1}) {
|
|
t.Fatal("Artwork must use white emission modulation", color, err)
|
|
}
|
|
want := float32(0)
|
|
if f == first {
|
|
want = 16
|
|
}
|
|
intensity, err := render2d.GetMaterialParameter(a.sc, a.sprite, "EmissionIntensity")
|
|
if err != nil || intensity.Kind != schema.KindFloat32 || intensity.F != float64(want) || a.Status().HasEmission != (f == first) {
|
|
t.Fatal("emission must follow the current frame's actual channel", f, intensity, err, a.Status())
|
|
}
|
|
} else if override, ok := scene.Get[render2d.MaterialOverride](a.sc, a.sprite); ok && len(override.Values) != 0 {
|
|
t.Fatal("Lit parameters remained on an incompatible preview shader", mode, override.Values)
|
|
}
|
|
floorColor, err := render2d.GetMaterialParameter(a.sc, a.floor, "EmissionColor")
|
|
if err != nil || floorColor.Kind != schema.KindColor || floorColor.C != (mathx.Color{A: 1}) {
|
|
t.Fatal("shadow receiver unexpectedly became emissive", floorColor, err)
|
|
}
|
|
floorIntensity, err := render2d.GetMaterialParameter(a.sc, a.floor, "EmissionIntensity")
|
|
if err != nil || floorIntensity.Kind != schema.KindFloat32 || floorIntensity.F != 0 || scene.Has[render2d.MaterialOverride](a.sc, a.floor) {
|
|
t.Fatal("Artwork preview changed receiver material parameters", floorIntensity, err)
|
|
}
|
|
if color, _ := base.Get("EmissionColor"); color != baseColor {
|
|
t.Fatal("shared Lit color changed")
|
|
}
|
|
if intensity, _ := base.Get("EmissionIntensity"); intensity != baseIntensity || base.Generation() != baseGeneration {
|
|
t.Fatal("preview changed shared material or shader generation")
|
|
}
|
|
}
|
|
}
|
|
after, err := d.Encode()
|
|
if err != nil || !bytes.Equal(before, after) {
|
|
t.Fatal("preview controls changed the canonical art document", err)
|
|
}
|
|
}
|