2014-10-02 13:25:02 +10:00
|
|
|
// 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.
|
|
|
|
|
2014-10-19 10:49:39 -04:00
|
|
|
// 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:
|
|
|
|
//
|
2015-06-18 15:29:31 +10:00
|
|
|
// golang.org/x/mobile/exp/sprite/portable
|
2014-10-19 10:49:39 -04:00
|
|
|
//
|
|
|
|
// 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.
|
2014-10-02 13:25:02 +10:00
|
|
|
//
|
|
|
|
// Typical main loop:
|
|
|
|
//
|
|
|
|
// for each frame {
|
2014-10-13 09:09:32 +11:00
|
|
|
// quantize time.Now() to a clock.Time
|
2014-10-02 13:25:02 +10:00
|
|
|
// process UI events
|
|
|
|
// modify the scene's nodes and animations (Arranger values)
|
app: use one thread for both GL and other UI C code.
This change will break Darwin. I have only built and tested this on
desktop linux and Android linux. A follow-up CL will fix Darwin.
Currently, OpenGL gets its own thread, and UI C code (e.g. the Android
event loop, or the X11 event loop) gets its own thread. This relies on
multiple system-provided UI-related C libraries working nicely together,
even when running on different threads. Keeping all the C code on the
one thread seems more sound.
As side-effects:
- In package app/debug, DrawFPS now takes an explicit Config.
- In package app, some callbacks now take an explicit Config.
- In package exp/sprite, Render now takes an explicit Config.
- In package event, there are new events (Config, Draw, Lifecycle),
and an event filter mechanism to replace multiple app Callbacks.
- In package geom, the deprecated Width, Height and PixelsPerPt global
variables were removed in favor of an event.Config that is
explicitly passed around (and does not require mutex-locking).
Converting a geom.Pt to pixels now requires passing a pixelsPerPt.
- In package gl, the Do, Start and Stop functions are removed, as well
as the need to call Start in its own goroutine. There is no longer a
separate GL thread. Instead, package app explicitly performs any GL
work (gl.DoWork) when some is available (gl.WorkAvailable).
- In package gl/glutil, Image.Draw now takes an explicit Config.
Callbacks are no longer executed on 'the UI thread'.
Changing the app programming model from callbacks to events (since a
channel of events works with select) will be a follow-up change.
Change-Id: Id9865cd9ee1c45a98c613e9021a63c17226a64b1
Reviewed-on: https://go-review.googlesource.com/11351
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-23 16:41:48 +10:00
|
|
|
// e.Render(scene, t, c)
|
2014-10-02 13:25:02 +10:00
|
|
|
// }
|
2015-06-18 15:29:31 +10:00
|
|
|
package sprite // import "golang.org/x/mobile/exp/sprite"
|
2014-10-02 13:25:02 +10:00
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
2014-11-11 20:46:47 -05:00
|
|
|
"image/draw"
|
2014-10-02 13:25:02 +10:00
|
|
|
|
app: use one thread for both GL and other UI C code.
This change will break Darwin. I have only built and tested this on
desktop linux and Android linux. A follow-up CL will fix Darwin.
Currently, OpenGL gets its own thread, and UI C code (e.g. the Android
event loop, or the X11 event loop) gets its own thread. This relies on
multiple system-provided UI-related C libraries working nicely together,
even when running on different threads. Keeping all the C code on the
one thread seems more sound.
As side-effects:
- In package app/debug, DrawFPS now takes an explicit Config.
- In package app, some callbacks now take an explicit Config.
- In package exp/sprite, Render now takes an explicit Config.
- In package event, there are new events (Config, Draw, Lifecycle),
and an event filter mechanism to replace multiple app Callbacks.
- In package geom, the deprecated Width, Height and PixelsPerPt global
variables were removed in favor of an event.Config that is
explicitly passed around (and does not require mutex-locking).
Converting a geom.Pt to pixels now requires passing a pixelsPerPt.
- In package gl, the Do, Start and Stop functions are removed, as well
as the need to call Start in its own goroutine. There is no longer a
separate GL thread. Instead, package app explicitly performs any GL
work (gl.DoWork) when some is available (gl.WorkAvailable).
- In package gl/glutil, Image.Draw now takes an explicit Config.
Callbacks are no longer executed on 'the UI thread'.
Changing the app programming model from callbacks to events (since a
channel of events works with select) will be a follow-up change.
Change-Id: Id9865cd9ee1c45a98c613e9021a63c17226a64b1
Reviewed-on: https://go-review.googlesource.com/11351
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-23 16:41:48 +10:00
|
|
|
"golang.org/x/mobile/event"
|
2015-07-02 17:20:49 +10:00
|
|
|
"golang.org/x/mobile/exp/f32"
|
2015-06-18 15:29:31 +10:00
|
|
|
"golang.org/x/mobile/exp/sprite/clock"
|
2014-10-02 13:25:02 +10:00
|
|
|
)
|
|
|
|
|
|
|
|
type Arranger interface {
|
2014-10-13 09:09:32 +11:00
|
|
|
Arrange(e Engine, n *Node, t clock.Time)
|
2014-10-02 13:25:02 +10:00
|
|
|
}
|
|
|
|
|
2014-11-11 20:46:47 -05:00
|
|
|
type Texture interface {
|
|
|
|
Bounds() (w, h int)
|
|
|
|
Download(r image.Rectangle, dst draw.Image)
|
|
|
|
Upload(r image.Rectangle, src image.Image)
|
|
|
|
Unload()
|
|
|
|
}
|
2014-10-02 13:25:02 +10:00
|
|
|
|
2014-11-11 20:46:47 -05:00
|
|
|
type SubTex struct {
|
|
|
|
T Texture
|
|
|
|
R image.Rectangle
|
|
|
|
}
|
2014-10-02 13:25:02 +10:00
|
|
|
|
|
|
|
type Engine interface {
|
|
|
|
Register(n *Node)
|
|
|
|
Unregister(n *Node)
|
|
|
|
|
2014-11-11 20:46:47 -05:00
|
|
|
LoadTexture(a image.Image) (Texture, error)
|
2014-10-02 13:25:02 +10:00
|
|
|
|
2014-11-11 20:46:47 -05:00
|
|
|
SetSubTex(n *Node, x SubTex)
|
|
|
|
SetTransform(n *Node, m f32.Affine) // sets transform relative to parent.
|
2014-10-02 13:25:02 +10:00
|
|
|
|
app: use one thread for both GL and other UI C code.
This change will break Darwin. I have only built and tested this on
desktop linux and Android linux. A follow-up CL will fix Darwin.
Currently, OpenGL gets its own thread, and UI C code (e.g. the Android
event loop, or the X11 event loop) gets its own thread. This relies on
multiple system-provided UI-related C libraries working nicely together,
even when running on different threads. Keeping all the C code on the
one thread seems more sound.
As side-effects:
- In package app/debug, DrawFPS now takes an explicit Config.
- In package app, some callbacks now take an explicit Config.
- In package exp/sprite, Render now takes an explicit Config.
- In package event, there are new events (Config, Draw, Lifecycle),
and an event filter mechanism to replace multiple app Callbacks.
- In package geom, the deprecated Width, Height and PixelsPerPt global
variables were removed in favor of an event.Config that is
explicitly passed around (and does not require mutex-locking).
Converting a geom.Pt to pixels now requires passing a pixelsPerPt.
- In package gl, the Do, Start and Stop functions are removed, as well
as the need to call Start in its own goroutine. There is no longer a
separate GL thread. Instead, package app explicitly performs any GL
work (gl.DoWork) when some is available (gl.WorkAvailable).
- In package gl/glutil, Image.Draw now takes an explicit Config.
Callbacks are no longer executed on 'the UI thread'.
Changing the app programming model from callbacks to events (since a
channel of events works with select) will be a follow-up change.
Change-Id: Id9865cd9ee1c45a98c613e9021a63c17226a64b1
Reviewed-on: https://go-review.googlesource.com/11351
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-23 16:41:48 +10:00
|
|
|
// Render renders the scene arranged at the given time, for the given
|
|
|
|
// window configuration (dimensions and resolution).
|
|
|
|
Render(scene *Node, t clock.Time, c event.Config)
|
2014-10-02 13:25:02 +10:00
|
|
|
}
|
|
|
|
|
2014-10-19 10:49:39 -04:00
|
|
|
// A Node is a renderable element and forms a tree of Nodes.
|
2014-10-02 13:25:02 +10:00
|
|
|
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?
|
2014-11-11 20:46:47 -05:00
|
|
|
Dirty bool
|
|
|
|
Index int32
|
|
|
|
SubTex SubTex
|
2014-10-02 13:25:02 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-19 10:49:39 -04:00
|
|
|
// 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
|
|
|
|
}
|