122 lines
2.9 KiB
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
|
|
}
|