github.com/champo/mobile@v0.0.0-20190107162257-dc0771356504/exp/sprite/sprite.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package sprite provides a 2D scene graph for rendering and animation.
     6  //
     7  // A tree of nodes is drawn by a rendering Engine, provided by another
     8  // package. The OS-independent Go version based on the image package is:
     9  //
    10  //	golang.org/x/mobile/exp/sprite/portable
    11  //
    12  // An Engine draws a screen starting at a root Node. The tree is walked
    13  // depth-first, with affine transformations applied at each level.
    14  //
    15  // Nodes are rendered relative to their parent.
    16  //
    17  // Typical main loop:
    18  //
    19  //	for each frame {
    20  //		quantize time.Now() to a clock.Time
    21  //		process UI events
    22  //		modify the scene's nodes and animations (Arranger values)
    23  //		e.Render(scene, t, sz)
    24  //	}
    25  package sprite // import "golang.org/x/mobile/exp/sprite"
    26  
    27  import (
    28  	"image"
    29  	"image/draw"
    30  
    31  	"golang.org/x/mobile/event/size"
    32  	"golang.org/x/mobile/exp/f32"
    33  	"golang.org/x/mobile/exp/sprite/clock"
    34  )
    35  
    36  type Arranger interface {
    37  	Arrange(e Engine, n *Node, t clock.Time)
    38  }
    39  
    40  type Texture interface {
    41  	Bounds() (w, h int)
    42  	Download(r image.Rectangle, dst draw.Image)
    43  	Upload(r image.Rectangle, src image.Image)
    44  	Release()
    45  }
    46  
    47  type SubTex struct {
    48  	T Texture
    49  	R image.Rectangle
    50  }
    51  
    52  type Engine interface {
    53  	Register(n *Node)
    54  	Unregister(n *Node)
    55  
    56  	LoadTexture(a image.Image) (Texture, error)
    57  
    58  	SetSubTex(n *Node, x SubTex)
    59  	SetTransform(n *Node, m f32.Affine) // sets transform relative to parent.
    60  
    61  	// Render renders the scene arranged at the given time, for the given
    62  	// window configuration (dimensions and resolution).
    63  	Render(scene *Node, t clock.Time, sz size.Event)
    64  
    65  	Release()
    66  }
    67  
    68  // A Node is a renderable element and forms a tree of Nodes.
    69  type Node struct {
    70  	Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
    71  
    72  	Arranger Arranger
    73  
    74  	// EngineFields contains fields that should only be accessed by Engine
    75  	// implementations. It is exported because such implementations can be
    76  	// in other packages.
    77  	EngineFields struct {
    78  		// TODO: separate TexDirty and TransformDirty bits?
    79  		Dirty  bool
    80  		Index  int32
    81  		SubTex SubTex
    82  	}
    83  }
    84  
    85  // AppendChild adds a node c as a child of n.
    86  //
    87  // It will panic if c already has a parent or siblings.
    88  func (n *Node) AppendChild(c *Node) {
    89  	if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
    90  		panic("sprite: AppendChild called for an attached child Node")
    91  	}
    92  	last := n.LastChild
    93  	if last != nil {
    94  		last.NextSibling = c
    95  	} else {
    96  		n.FirstChild = c
    97  	}
    98  	n.LastChild = c
    99  	c.Parent = n
   100  	c.PrevSibling = last
   101  }
   102  
   103  // RemoveChild removes a node c that is a child of n. Afterwards, c will have
   104  // no parent and no siblings.
   105  //
   106  // It will panic if c's parent is not n.
   107  func (n *Node) RemoveChild(c *Node) {
   108  	if c.Parent != n {
   109  		panic("sprite: RemoveChild called for a non-child Node")
   110  	}
   111  	if n.FirstChild == c {
   112  		n.FirstChild = c.NextSibling
   113  	}
   114  	if c.NextSibling != nil {
   115  		c.NextSibling.PrevSibling = c.PrevSibling
   116  	}
   117  	if n.LastChild == c {
   118  		n.LastChild = c.PrevSibling
   119  	}
   120  	if c.PrevSibling != nil {
   121  		c.PrevSibling.NextSibling = c.NextSibling
   122  	}
   123  	c.Parent = nil
   124  	c.PrevSibling = nil
   125  	c.NextSibling = nil
   126  }