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 }