Files
aego/tests/lightinggolden/resources.go
T
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

180 lines
5.8 KiB
Go

package lightinggolden
import (
"embed"
"fmt"
"aego/asset"
"aego/core/ids"
"aego/core/mathx"
"aego/gpu"
"aego/render"
"aego/render/lighting"
"aego/render/material"
"aego/render/texture"
)
//go:embed fixtures/*.aesh
var preparedFixtures embed.FS
func RunSurfaceResources(g *Rig, report *Report) {
RunEmissionChannels(g, report)
report.Case("normal-own-atlas-region-trim-and-frame-mapping", func() error {
// An unrelated island intentionally surrounds the normal. Sampling the
// albedo UV or reading past the normal rectangle gives a distinct normal.
pixels := make([]byte, 16*8*4)
for y := 0; y < 8; y++ {
for x := 0; x < 16; x++ {
i := (y*16 + x) * 4
pixels[i], pixels[i+1], pixels[i+2], pixels[i+3] = 255, 128, 128, 255
if x >= 10 && x < 14 && y >= 2 && y < 6 {
pixels[i], pixels[i+1], pixels[i+2] = 191, 223, 223
}
}
}
nh, err := g.Texture(gpu.TextureDesc{Width: 16, Height: 8, Format: gpu.TexRGBA8, Data: pixels})
if err != nil {
return err
}
for i := range pixels {
pixels[i] = 255
}
ah, err := g.Texture(gpu.TextureDesc{Width: 16, Height: 8, Format: gpu.TexRGBA8, Data: pixels})
if err != nil {
return err
}
normal := texture.Whole(nh, 16, 8).Sub(10, 2, 4, 4)
normal.SourceW, normal.SourceH, normal.TrimX, normal.TrimY = 8, 8, 2, 2
albedo := texture.Whole(ah, 16, 8).Sub(0, 0, 4, 8)
albedo.SourceW, albedo.SourceH, albedo.TrimX = 8, 8, 2
d := g.Sprite(g.Lit)
d.Region = albedo
d.Normal = normal
in := Input(lighting.LDR)
in.Debug = lighting.DebugNormals
s := WhiteSurface()
s.Width = 12
s.NormalAt = func(u, v float64) [3]float64 {
if v < .25 || v > .75 {
return [3]float64{0, 0, 1}
}
return NormalReference([3]byte{191, 223, 223}, s.Basis, false, false)
}
got, err := g.Draw(&in, func(v *render.ViewFrame) { v.Sprite(d) })
if err != nil {
return err
}
if err = report.Image("normal-own-atlas-region-trim-and-frame-mapping", got, Reference(in, [4]float64{}, s), 2); err != nil {
return err
}
// A later frame can have another independently packed normal rectangle.
d.Normal = texture.Whole(nh, 16, 8).Sub(2, 1, 4, 4)
s.NormalAt = nil
s.Normal = NormalReference([3]byte{255, 128, 128}, s.Basis, false, false)
got, err = g.Draw(&in, func(v *render.ViewFrame) { v.Sprite(d) })
if err != nil {
return err
}
if err = report.Image("normal-second-frame-own-region", got, Reference(in, [4]float64{}, s), 2); err != nil {
return err
}
d.Normal = texture.Region{}
s.Normal = [3]float64{0, 0, 1}
got, err = g.Draw(&in, func(v *render.ViewFrame) { v.Sprite(d) })
if err != nil {
return err
}
return report.Image("normal-missing-frame-flat", got, Reference(in, [4]float64{}, s), 2)
})
report.Case("six-user-samplers-plus-normal-emission-shadow-cookie", func() error {
data, err := preparedFixtures.ReadFile("fixtures/resources.aesh")
if err != nil {
return err
}
artifact, err := asset.DecodeShader(data)
if err != nil {
return err
}
sh := artifact.Runtime(ids.AssetID{}, "lighting-six-samplers")
m, ok := material.New("lighting-six-samplers", sh, 0, sh.Blend)
if !ok {
return fmt.Errorf("cannot create fixture material")
}
for i, name := range []string{"One", "Two", "Three", "Four", "Five", "Six"} {
r := []byte{47, 71, 97, 131, 173, 223}[i]
h, err := g.Texture(gpu.TextureDesc{Width: 1, Height: 1, Format: gpu.TexRGBA8, Data: []byte{r, 0, 0, 255}})
if err != nil {
return err
}
if !m.SetTexture(name, material.Tex{Texture: h}) {
return fmt.Errorf("failed to bind %s", name)
}
}
if !m.SetTexture("NormalMap", material.Tex{Texture: g.Normal.Texture, Region: g.Normal, NormalMap: true}) {
return fmt.Errorf("normal reserved binding rejected")
}
eh, err := g.Texture(gpu.TextureDesc{Width: 1, Height: 1, Format: gpu.TexRGBA8, Data: []byte{128, 128, 128, 0}})
if err != nil {
return err
}
if !m.SetTexture("EmissionMap", material.Tex{Texture: eh, EmissionMode: texture.EmissionRGB}) {
return fmt.Errorf("emission reserved binding rejected")
}
in := ShadowInput(lighting.Sprite)
in.Lights[0].Cookie = g.Cookie
d := g.Sprite(m)
s := WhiteSurface()
s.Normal = NormalReference([3]byte{191, 223, 223}, s.Basis, false, false)
s.Emission = [3]float64{.1 * 128 / 255, .15 * 128 / 255, .2 * 128 / 255}
got, err := g.Draw(&in, func(v *render.ViewFrame) { v.Sprite(d) })
if err != nil {
return err
}
return report.Image("six-user-samplers-plus-normal-emission-shadow-cookie", got, Reference(in, [4]float64{}, s), 2)
})
report.Case("shadow-array-layer-preview-is-real-resource", func() error {
h, err := g.Texture(gpu.TextureDesc{Width: Size, Height: Size, Format: gpu.TexRGBA8})
if err != nil {
return err
}
in := ShadowInput(lighting.Point)
in.Lights[0].Position = mathx.Vec2{X: 16, Y: 6}
in.Points = []mathx.Vec2{{X: -64, Y: 15}, {X: 96, Y: 15}}
d := g.Sprite(g.Lit)
frame := g.Device.BeginFrame(Size, Size)
if err = g.Renderer.BeginFrame(frame, Size, Size, 1); err != nil {
return err
}
v := g.Renderer.View(g.View())
v.Lighting(&in)
v.Sprite(d)
v.End()
layers := g.Renderer.LightingShadowLayers(g.View().ID, nil)
if len(layers) != 1 {
return fmt.Errorf("active shadow layers %v", layers)
}
err = g.Renderer.PreviewShadowLayer(g.View().ID, layers[0].Layer, h, Size, Size)
g.Renderer.EndFrame()
g.Device.EndFrame()
if err != nil {
return err
}
if err = g.Device.ReadPixels(h, 0, 0, Size, Size, g.Pixels); err != nil {
return err
}
want := make([]byte, Size*Size*4)
for y := 0; y < Size; y++ {
for x := 0; x < Size; x++ {
i := (y*Size + x) * 4
c := byte(255)
worldY := 6 - 40 + (float64(y)+.5)*80/Size
if worldY >= 15 {
c = 0
}
want[i], want[i+1], want[i+2], want[i+3] = c, c, c, 255
}
}
return report.Image("shadow-array-layer-preview-is-real-resource", g.Pixels, want, 1)
})
}