Files
aego/scene/space_test.go
T
sanspie 17cb5e4291 Stage 2-5: assets, scene/ECS, editor, 3D, and Aego Script
Stage 2: render pipeline and UI toolkit over gpu/platform.
Stage 3: schema registry, asset pipeline + runtime loader, scene graph and ECS.
Stage 4: editor — docking, inspector, scene/game views, play mode, asset browser, console, profiler; 4.5 adds the 3D foundation (mixed 2D/3D spaces, meshes, depth).
Stage 5: Aego Script — compiler (lexer/parser/types/resolver/checker/asm/compiler), bytecode with verifier and register VM, instance runtime, stdlib, native bindings, and editor/CLI integration (aego run/edit/check/test/dump).
2026-10-08 13:17:28 +03:00

102 lines
2.9 KiB
Go

package scene
import (
"testing"
"aego/core/ids"
"aego/core/mathx"
"aego/schema"
)
func spaceScene(t *testing.T) *Scene {
t.Helper()
types := NewTypes(schema.NewRegistry())
if err := types.Schema().Freeze(); err != nil {
t.Fatal(err)
}
return New(types, nil, Options{})
}
func createIn(t *testing.T, s *Scene, parent NodeHandle, name string, sp Space) NodeHandle {
t.Helper()
h, err := s.CreateIn(parent, name, ids.NodeID{}, sp)
if err != nil {
t.Fatal(err)
}
return h
}
func TestSpaceInheritance(t *testing.T) {
s := spaceScene(t)
a := s.Create3D(s.Root(), "a")
if b := s.Create(a, "b"); s.Space(b) != Space3D {
t.Fatal("child of a 3D node must inherit 3D")
}
c := createIn(t, s, a, "c", Space2D)
if s.Space(c) != Space2D || !s.Under3D(c) {
t.Fatal("2D child under 3D parent must be allowed and marked Under3D")
}
if flat := s.Create(s.Root(), "flat"); s.Space(flat) != Space2D {
t.Fatal("root children default to the scene space")
}
}
func TestSpaceMismatchRejected(t *testing.T) {
s := spaceScene(t)
p := s.Create(s.Root(), "p")
if s.AllowsSpace(p, Space3D) {
t.Fatal("2D parent must not allow a 3D child")
}
h, err := s.CreateIn(p, "x", ids.NodeID{}, Space3D)
if err == nil || !h.IsZero() {
t.Fatalf("3D node under a 2D parent: handle %v err %v", h, err)
}
}
func TestMixedWorldTransform(t *testing.T) {
s := spaceScene(t)
a := s.Create3D(s.Root(), "a")
s.SetLocal3D(a, Transform3D{
Position: mathx.Vec3{X: 1, Y: 2, Z: 3},
Rotation: mathx.QuatAxisAngle(mathx.Vec3{Y: 1}, mathx.Pi/2),
Scale: mathx.Vec3{X: 1, Y: 1, Z: 1},
})
c := createIn(t, s, a, "c", Space2D)
s.SetPosition(c, mathx.Vec2{X: 2, Y: 1})
g := createIn(t, s, c, "g", Space2D)
s.SetPosition(g, mathx.Vec2{X: 1})
s.Flush()
s.UpdateTransforms()
want := s.World4(a).TransformPoint(mathx.Vec3{X: 2, Y: -1})
if got := s.World4(c).TransformPoint(mathx.Vec3{}); !got.NearlyEqual(want, 1e-5) {
t.Fatalf("2D under 3D: got %v want %v", got, want)
}
want = s.World4(a).TransformPoint(mathx.Vec3{X: 3, Y: -1})
if got := s.World4(g).TransformPoint(mathx.Vec3{}); !got.NearlyEqual(want, 1e-5) {
t.Fatalf("2D chain under 3D: got %v want %v", got, want)
}
s.SetPosition3D(a, mathx.Vec3{})
s.UpdateTransforms()
want = s.World4(a).TransformPoint(mathx.Vec3{X: 3, Y: -1})
if got := s.World4(g).TransformPoint(mathx.Vec3{}); !got.NearlyEqual(want, 1e-5) {
t.Fatalf("dirty propagation through the mixed chain: got %v want %v", got, want)
}
}
func TestSetSpaceRules(t *testing.T) {
s := spaceScene(t)
a := s.Create3D(s.Root(), "a")
s.Create(a, "child")
if err := s.SetSpace(a, Space2D); err == nil {
t.Fatal("space change on a node with children must fail")
}
leaf := s.Create(s.Root(), "leaf")
s.SetPosition(leaf, mathx.Vec2{X: 4, Y: 2})
if err := s.SetSpace(leaf, Space3D); err != nil {
t.Fatal(err)
}
if p := s.Local3D(leaf).Position; !p.NearlyEqual(mathx.Vec3{X: 4, Y: -2}, 1e-5) {
t.Fatalf("lift must map y to -y: %v", p)
}
}