github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/sprite/glsprite/glsprite.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 glsprite implements a sprite Engine using OpenGL ES 2.
     6  //
     7  // Each sprite.Texture is loaded as a GL texture object and drawn
     8  // to the screen via an affine transform done in a simple shader.
     9  package glsprite // import "golang.org/x/mobile/sprite/glsprite"
    10  
    11  import (
    12  	"image"
    13  	"image/draw"
    14  
    15  	"golang.org/x/mobile/f32"
    16  	"golang.org/x/mobile/geom"
    17  	"golang.org/x/mobile/gl/glutil"
    18  	"golang.org/x/mobile/sprite"
    19  	"golang.org/x/mobile/sprite/clock"
    20  )
    21  
    22  type node struct {
    23  	// TODO: move this into package sprite as Node.EngineFields.RelTransform??
    24  	relTransform f32.Affine
    25  }
    26  
    27  type texture struct {
    28  	glImage *glutil.Image
    29  	b       image.Rectangle
    30  }
    31  
    32  func (t *texture) Bounds() (w, h int) { return t.b.Dx(), t.b.Dy() }
    33  
    34  func (t *texture) Download(r image.Rectangle, dst draw.Image) {
    35  	panic("TODO")
    36  }
    37  
    38  func (t *texture) Upload(r image.Rectangle, src image.Image) {
    39  	draw.Draw(t.glImage.RGBA, r, src, src.Bounds().Min, draw.Src)
    40  	t.glImage.Upload()
    41  }
    42  
    43  func (t *texture) Unload() {
    44  	panic("TODO")
    45  }
    46  
    47  func Engine() sprite.Engine {
    48  	return &engine{
    49  		nodes: []*node{nil},
    50  	}
    51  }
    52  
    53  type engine struct {
    54  	glImages map[sprite.Texture]*glutil.Image
    55  	nodes    []*node
    56  
    57  	absTransforms []f32.Affine
    58  }
    59  
    60  func (e *engine) Register(n *sprite.Node) {
    61  	if n.EngineFields.Index != 0 {
    62  		panic("glsprite: sprite.Node already registered")
    63  	}
    64  	o := &node{}
    65  	o.relTransform.Identity()
    66  
    67  	e.nodes = append(e.nodes, o)
    68  	n.EngineFields.Index = int32(len(e.nodes) - 1)
    69  }
    70  
    71  func (e *engine) Unregister(n *sprite.Node) {
    72  	panic("todo")
    73  }
    74  
    75  func (e *engine) LoadTexture(src image.Image) (sprite.Texture, error) {
    76  	b := src.Bounds()
    77  	t := &texture{glutil.NewImage(b.Dx(), b.Dy()), b}
    78  	t.Upload(b, src)
    79  	// TODO: set "glImage.Pix = nil"?? We don't need the CPU-side image any more.
    80  	return t, nil
    81  }
    82  
    83  func (e *engine) SetSubTex(n *sprite.Node, x sprite.SubTex) {
    84  	n.EngineFields.Dirty = true // TODO: do we need to propagate dirtiness up/down the tree?
    85  	n.EngineFields.SubTex = x
    86  }
    87  
    88  func (e *engine) SetTransform(n *sprite.Node, m f32.Affine) {
    89  	n.EngineFields.Dirty = true // TODO: do we need to propagate dirtiness up/down the tree?
    90  	e.nodes[n.EngineFields.Index].relTransform = m
    91  }
    92  
    93  func (e *engine) Render(scene *sprite.Node, t clock.Time) {
    94  	e.absTransforms = append(e.absTransforms[:0], f32.Affine{
    95  		{1, 0, 0},
    96  		{0, 1, 0},
    97  	})
    98  	e.render(scene, t)
    99  }
   100  
   101  func (e *engine) render(n *sprite.Node, t clock.Time) {
   102  	if n.EngineFields.Index == 0 {
   103  		panic("glsprite: sprite.Node not registered")
   104  	}
   105  	if n.Arranger != nil {
   106  		n.Arranger.Arrange(e, n, t)
   107  	}
   108  
   109  	// Push absTransforms.
   110  	// TODO: cache absolute transforms and use EngineFields.Dirty?
   111  	rel := &e.nodes[n.EngineFields.Index].relTransform
   112  	m := f32.Affine{}
   113  	m.Mul(&e.absTransforms[len(e.absTransforms)-1], rel)
   114  	e.absTransforms = append(e.absTransforms, m)
   115  
   116  	if x := n.EngineFields.SubTex; x.T != nil {
   117  		x.T.(*texture).glImage.Draw(
   118  			geom.Point{
   119  				geom.Pt(m[0][2]),
   120  				geom.Pt(m[1][2]),
   121  			},
   122  			geom.Point{
   123  				geom.Pt(m[0][2] + m[0][0]),
   124  				geom.Pt(m[1][2] + m[1][0]),
   125  			},
   126  			geom.Point{
   127  				geom.Pt(m[0][2] + m[0][1]),
   128  				geom.Pt(m[1][2] + m[1][1]),
   129  			},
   130  			x.R,
   131  		)
   132  	}
   133  
   134  	for c := n.FirstChild; c != nil; c = c.NextSibling {
   135  		e.render(c, t)
   136  	}
   137  
   138  	// Pop absTransforms.
   139  	e.absTransforms = e.absTransforms[:len(e.absTransforms)-1]
   140  }