mobile/sprite/sprite.go

122 lines
2.9 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sprite provides a 2D scene graph for rendering and animation.
//
// A tree of nodes is drawn by a rendering Engine, provided by another
// package. The OS-independent Go version based on the image package is:
//
// code.google.com/p/go.mobile/sprite/portable
//
// An Engine draws a screen starting at a root Node. The tree is walked
// depth-first, with affine transformations applied at each level.
//
// Nodes are rendered relative to their parent.
//
// Typical main loop:
//
// for each frame {
// quantize time.Now() to a clock.Time
// process UI events
// modify the scene's nodes and animations (Arranger values)
// e.Render(scene, t)
// }
package sprite
import (
"image"
"image/draw"
"golang.org/x/mobile/f32"
"golang.org/x/mobile/sprite/clock"
)
type Arranger interface {
Arrange(e Engine, n *Node, t clock.Time)
}
type Texture interface {
Bounds() (w, h int)
Download(r image.Rectangle, dst draw.Image)
Upload(r image.Rectangle, src image.Image)
Unload()
}
type SubTex struct {
T Texture
R image.Rectangle
}
type Engine interface {
Register(n *Node)
Unregister(n *Node)
LoadTexture(a image.Image) (Texture, error)
SetSubTex(n *Node, x SubTex)
SetTransform(n *Node, m f32.Affine) // sets transform relative to parent.
Render(scene *Node, t clock.Time)
}
// A Node is a renderable element and forms a tree of Nodes.
type Node struct {
Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
Arranger Arranger
// EngineFields contains fields that should only be accessed by Engine
// implementations. It is exported because such implementations can be
// in other packages.
EngineFields struct {
// TODO: separate TexDirty and TransformDirty bits?
Dirty bool
Index int32
SubTex SubTex
}
}
// AppendChild adds a node c as a child of n.
//
// It will panic if c already has a parent or siblings.
func (n *Node) AppendChild(c *Node) {
if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
panic("sprite: AppendChild called for an attached child Node")
}
last := n.LastChild
if last != nil {
last.NextSibling = c
} else {
n.FirstChild = c
}
n.LastChild = c
c.Parent = n
c.PrevSibling = last
}
// RemoveChild removes a node c that is a child of n. Afterwards, c will have
// no parent and no siblings.
//
// It will panic if c's parent is not n.
func (n *Node) RemoveChild(c *Node) {
if c.Parent != n {
panic("sprite: RemoveChild called for a non-child Node")
}
if n.FirstChild == c {
n.FirstChild = c.NextSibling
}
if c.NextSibling != nil {
c.NextSibling.PrevSibling = c.PrevSibling
}
if n.LastChild == c {
n.LastChild = c.PrevSibling
}
if c.PrevSibling != nil {
c.PrevSibling.NextSibling = c.NextSibling
}
c.Parent = nil
c.PrevSibling = nil
c.NextSibling = nil
}