Files
aego/scene/keyframe.go

229 lines
4.9 KiB
Go

package scene
import (
"unsafe"
"aego/core/handle"
"aego/core/ids"
"aego/core/rewind"
"aego/schema"
)
var _ rewind.Keyframer = (*Scene)(nil)
type idEntry struct {
id ids.NodeID
h NodeHandle
}
type nameEntry struct {
key nameKey
h NodeHandle
}
type sceneKey struct {
nodes handle.Arena[nodeData]
byID []idEntry
byName []nameEntry
three []node3
free3 []int32
pres []presEntry
space Space
stores []rewind.Key
size int
}
func (k *sceneKey) Size() int {
return k.size
}
func keySlots[T any](s []T, n int) []T {
if cap(s) < n {
s = append(s[:cap(s)], make([]T, n-cap(s))...)
}
return s[:n]
}
func (s *Scene) Capture(reuse rewind.Key) rewind.Key {
k, _ := reuse.(*sceneKey)
if k == nil {
k = &sceneKey{}
}
s.nodes.CopyTo(&k.nodes)
k.byID = k.byID[:0]
for id, h := range s.byID {
k.byID = append(k.byID, idEntry{id: id, h: h})
}
k.byName = k.byName[:0]
for key, h := range s.byName {
k.byName = append(k.byName, nameEntry{key: key, h: h})
}
k.three = append(k.three[:0], s.three...)
k.free3 = append(k.free3[:0], s.free3...)
k.pres = append(k.pres[:0], s.pres...)
k.space = s.defaultSpace
k.stores = keySlots(k.stores, len(s.storeList))
k.size = int(unsafe.Sizeof(*k)) +
k.nodes.Slots()*int(unsafe.Sizeof(nodeData{})) +
len(k.byID)*int(unsafe.Sizeof(idEntry{})) +
len(k.byName)*int(unsafe.Sizeof(nameEntry{})) +
len(k.three)*int(unsafe.Sizeof(node3{}))
for i, st := range s.storeList {
k.stores[i] = st.capture(k.stores[i])
k.size += k.stores[i].Size()
}
return k
}
func (s *Scene) Restore(key rewind.Key) {
k := key.(*sceneKey)
s.nodes.RestoreFrom(&k.nodes)
clear(s.byID)
for _, e := range k.byID {
s.byID[e.id] = e.h
}
clear(s.byName)
for _, e := range k.byName {
s.byName[e.key] = e.h
}
s.three = append(s.three[:0], k.three...)
s.free3 = append(s.free3[:0], k.free3...)
s.pres = append(s.pres[:0], k.pres...)
s.render = s.render[:0]
s.presDirty, s.presActive = true, true
s.defaultSpace = k.space
for i, st := range s.storeList {
var sk rewind.Key
if i < len(k.stores) {
sk = k.stores[i]
}
st.restore(sk)
}
s.ops, s.pendingOps = s.ops[:0], 0
s.orderDirty = true
s.revision++
s.structureRev++
s.tags, s.tagsChecked = nil, false
s.emit(Event{Kind: EvHierarchyChanged})
}
func hashHandle(h *rewind.Hasher, n NodeHandle) {
h.U32(n.Index)
h.U32(n.Gen)
}
func (s *Scene) Hash(h *rewind.Hasher) {
h.String("scene")
s.nodes.HashTo(h)
h.Int(int(s.defaultSpace))
for _, nh := range s.PreOrder() {
n, ok := s.nodes.Get(nh)
if !ok {
continue
}
hashHandle(h, nh)
if nh != s.root {
h.U64(n.id.Hi)
h.U64(n.id.Lo)
}
h.String(s.interner.String(n.name))
hashHandle(h, n.parent)
hashHandle(h, n.firstChild)
hashHandle(h, n.nextSib)
l := &n.local
h.F32(l.Position.X)
h.F32(l.Position.Y)
h.F32(l.Rotation)
h.F32(l.Scale.X)
h.F32(l.Scale.Y)
h.U64(n.layers)
h.U32(uint32(n.flags & (flagAlive | flagEnabled | flagPendingDestroy)))
h.Int(int(n.space))
h.Int(int(n.childCount))
if n.slot >= 0 {
t := &s.three[n.slot].local
h.F32(t.Position.X)
h.F32(t.Position.Y)
h.F32(t.Position.Z)
h.F32(t.Rotation.X)
h.F32(t.Rotation.Y)
h.F32(t.Rotation.Z)
h.F32(t.Rotation.W)
h.F32(t.Scale.X)
h.F32(t.Scale.Y)
h.F32(t.Scale.Z)
}
}
h.Int(len(s.free3))
for _, f := range s.free3 {
h.U32(uint32(f))
}
for _, st := range s.storeList {
if st.count() > 0 {
st.hash(h)
}
}
}
type storeKey[T any] struct {
nodes []NodeHandle
data []T
sparse []int32
}
func (k *storeKey[T]) Size() int {
var zero T
return len(k.nodes)*int(unsafe.Sizeof(NodeHandle{})) + len(k.data)*int(unsafe.Sizeof(zero)) + 4*len(k.sparse)
}
func cloneData[T any](dst, src []T, td *schema.TypeDescriptor) []T {
if len(dst) > len(src) {
clear(dst[len(src):])
}
if td.Flat || td.CloneInto == nil {
return append(dst[:0], src...)
}
dst = keySlots(dst, len(src))
for i := range src {
td.CloneInto(unsafe.Pointer(&dst[i]), unsafe.Pointer(&src[i]))
}
return dst
}
func (c *ComponentStore[T]) capture(reuse rewind.Key) rewind.Key {
k, _ := reuse.(*storeKey[T])
if k == nil {
k = &storeKey[T]{}
}
k.nodes = append(k.nodes[:0], c.nodes...)
k.sparse = append(k.sparse[:0], c.sparse.dense...)
k.data = cloneData(k.data, c.data, c.desc)
return k
}
func (c *ComponentStore[T]) restore(key rewind.Key) {
c.pending = c.pending[:0]
for i := range c.chunks {
c.chunks[i] = c.chunks[i][:0]
}
c.dead = c.dead[:0]
k, _ := key.(*storeKey[T])
if k == nil {
clear(c.data)
c.data, c.nodes, c.sparse.dense = c.data[:0], c.nodes[:0], c.sparse.dense[:0]
return
}
c.nodes = append(c.nodes[:0], k.nodes...)
c.sparse.dense = append(c.sparse.dense[:0], k.sparse...)
c.data = cloneData(c.data, k.data, c.desc)
}
func (c *ComponentStore[T]) hash(h *rewind.Hasher) {
h.String(c.desc.FullName)
h.Int(len(c.data))
for i := range c.data {
hashHandle(h, c.nodes[i])
schema.HashFields(h, c.desc, unsafe.Pointer(&c.data[i]))
}
}