| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- // 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.
- //go:build darwin || linux || windows
- // +build darwin linux windows
- // Package glsprite implements a sprite Engine using OpenGL ES 2.
- //
- // Each sprite.Texture is loaded as a GL texture object and drawn
- // to the screen via an affine transform done in a simple shader.
- package glsprite // import "golang.org/x/mobile/exp/sprite/glsprite"
- import (
- "image"
- "image/draw"
- "golang.org/x/mobile/event/size"
- "golang.org/x/mobile/exp/f32"
- "golang.org/x/mobile/exp/gl/glutil"
- "golang.org/x/mobile/exp/sprite"
- "golang.org/x/mobile/exp/sprite/clock"
- "golang.org/x/mobile/geom"
- )
- type node struct {
- // TODO: move this into package sprite as Node.EngineFields.RelTransform??
- relTransform f32.Affine
- }
- type texture struct {
- e *engine
- glImage *glutil.Image
- b image.Rectangle
- }
- func (t *texture) Bounds() (w, h int) { return t.b.Dx(), t.b.Dy() }
- func (t *texture) Download(r image.Rectangle, dst draw.Image) {
- panic("TODO")
- }
- func (t *texture) Upload(r image.Rectangle, src image.Image) {
- draw.Draw(t.glImage.RGBA, r, src, src.Bounds().Min, draw.Src)
- t.glImage.Upload()
- }
- func (t *texture) Release() {
- t.glImage.Release()
- delete(t.e.textures, t)
- }
- // Engine creates an OpenGL-based sprite.Engine.
- func Engine(images *glutil.Images) sprite.Engine {
- return &engine{
- nodes: []*node{nil},
- images: images,
- textures: make(map[*texture]struct{}),
- }
- }
- type engine struct {
- images *glutil.Images
- textures map[*texture]struct{}
- nodes []*node
- absTransforms []f32.Affine
- }
- func (e *engine) Register(n *sprite.Node) {
- if n.EngineFields.Index != 0 {
- panic("glsprite: sprite.Node already registered")
- }
- o := &node{}
- o.relTransform.Identity()
- e.nodes = append(e.nodes, o)
- n.EngineFields.Index = int32(len(e.nodes) - 1)
- }
- func (e *engine) Unregister(n *sprite.Node) {
- panic("todo")
- }
- func (e *engine) LoadTexture(src image.Image) (sprite.Texture, error) {
- b := src.Bounds()
- t := &texture{
- e: e,
- glImage: e.images.NewImage(b.Dx(), b.Dy()),
- b: b,
- }
- e.textures[t] = struct{}{}
- t.Upload(b, src)
- // TODO: set "glImage.Pix = nil"?? We don't need the CPU-side image any more.
- return t, nil
- }
- func (e *engine) SetSubTex(n *sprite.Node, x sprite.SubTex) {
- n.EngineFields.Dirty = true // TODO: do we need to propagate dirtiness up/down the tree?
- n.EngineFields.SubTex = x
- }
- func (e *engine) SetTransform(n *sprite.Node, m f32.Affine) {
- n.EngineFields.Dirty = true // TODO: do we need to propagate dirtiness up/down the tree?
- e.nodes[n.EngineFields.Index].relTransform = m
- }
- func (e *engine) Render(scene *sprite.Node, t clock.Time, sz size.Event) {
- e.absTransforms = append(e.absTransforms[:0], f32.Affine{
- {1, 0, 0},
- {0, 1, 0},
- })
- e.render(scene, t, sz)
- }
- func (e *engine) render(n *sprite.Node, t clock.Time, sz size.Event) {
- if n.EngineFields.Index == 0 {
- panic("glsprite: sprite.Node not registered")
- }
- if n.Arranger != nil {
- n.Arranger.Arrange(e, n, t)
- }
- // Push absTransforms.
- // TODO: cache absolute transforms and use EngineFields.Dirty?
- rel := &e.nodes[n.EngineFields.Index].relTransform
- m := f32.Affine{}
- m.Mul(&e.absTransforms[len(e.absTransforms)-1], rel)
- e.absTransforms = append(e.absTransforms, m)
- if x := n.EngineFields.SubTex; x.T != nil {
- x.T.(*texture).glImage.Draw(
- sz,
- geom.Point{
- geom.Pt(m[0][2]),
- geom.Pt(m[1][2]),
- },
- geom.Point{
- geom.Pt(m[0][2] + m[0][0]),
- geom.Pt(m[1][2] + m[1][0]),
- },
- geom.Point{
- geom.Pt(m[0][2] + m[0][1]),
- geom.Pt(m[1][2] + m[1][1]),
- },
- x.R,
- )
- }
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- e.render(c, t, sz)
- }
- // Pop absTransforms.
- e.absTransforms = e.absTransforms[:len(e.absTransforms)-1]
- }
- func (e *engine) Release() {
- for img := range e.textures {
- img.Release()
- }
- }
|