gomobile bind works

This commit is contained in:
Hajime Hoshi 2016-05-19 23:37:58 +09:00
parent 296282435a
commit 6d06b01cae
10 changed files with 138 additions and 55 deletions

View File

@ -17,8 +17,6 @@
package mobile
import (
_ "image/jpeg"
"log"
"math"
"github.com/hajimehoshi/ebiten"
@ -49,11 +47,16 @@ func update(screen *ebiten.Image) error {
return nil
}
func Start() {
func Start() error {
var err error
gophersImage, _, err = common.AssetImage("gophers.jpg", ebiten.FilterNearest)
if err != nil {
log.Fatal(err)
return err
}
mobile.Start(update, screenWidth, screenHeight, 2, "Mobile (Ebiten Demo)")
return nil
}
func Render() error {
return mobile.Render()
}

View File

@ -14,6 +14,11 @@
package ebiten
import (
"github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/ui"
)
func newGraphicsContext(f func(*Image) error) *graphicsContext {
return &graphicsContext{
f: f,
@ -25,6 +30,7 @@ type graphicsContext struct {
screen *Image
defaultRenderTarget *Image
screenScale int
imageTasksDone bool
}
func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) error {
@ -49,6 +55,17 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) er
}
func (c *graphicsContext) Update() error {
if !c.imageTasksDone {
if err := graphics.Initialize(ui.GLContext()); err != nil {
return err
}
// This execution is called here because we can say actual GL function calls
// should be done here (especailly on mobiles).
if err := theDelayedImageTasks.exec(); err != nil {
return err
}
c.imageTasksDone = true
}
if err := c.screen.Clear(); err != nil {
return err
}

View File

@ -561,10 +561,6 @@ func newImageWithZeroFramebuffer(width, height int) (*Image, error) {
if err != nil {
return nil, err
}
// When this is called, OpenGL context should exist.
if err := theDelayedImageTasks.exec(); err != nil {
return nil, err
}
return img, nil
}

View File

@ -41,10 +41,12 @@ func (p Program) id() programID {
}
type context struct {
gl mgl.Context
gl mgl.Context
worker mgl.Worker
initialized chan struct{}
}
func NewContext() *Context {
func NewContext() (*Context, error) {
c := &Context{
Nearest: mgl.NEAREST,
Linear: mgl.LINEAR,
@ -65,21 +67,28 @@ func NewContext() *Context {
locationCache: newLocationCache(),
lastCompositeMode: CompositeModeUnknown,
}
return c
c.gl, c.worker = mgl.NewContext()
c.initialized = make(chan struct{})
go func() {
// GL calls will just enqueue an task to the worker.
// Since the worker is not avaialbe, this enqueuing should be done
// in a goroutine.
// Textures' pixel formats are alpha premultiplied.
c.gl.Enable(mgl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
close(c.initialized)
}()
return c, nil
}
func (c *Context) SetContext(gl mgl.Context) {
c.gl = gl
if gl == nil {
return
}
// Textures' pixel formats are alpha premultiplied.
gl.Enable(mgl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
func (c *Context) WaitUntilInitializingDone() {
// TODO: Call this function at an approriate place
<-c.initialized
}
func (c *Context) IsGLContextNil() bool {
return c.gl == nil
func (c *Context) Worker() mgl.Worker {
return c.worker
}
func (c *Context) BlendFunc(mode CompositeMode) {

View File

@ -150,6 +150,9 @@ func Run(g GraphicsContext, width, height, scale int, title string, fps int) err
beforeForUpdate += int64(tt) * int64(time.Second) / int64(fps)
frames++
}
if err := ui.CurrentUI().FinishRendering(); err != nil {
return err
}
// Calc the current FPS.
if time.Second <= time.Duration(n2-beforeForFPS) {

View File

@ -18,6 +18,7 @@ type UserInterface interface {
Start(width, height, scale int, title string) error
Update() (interface{}, error)
SwapBuffers() error
FinishRendering() error
Terminate() error
ScreenScale() int
SetScreenSize(width, height int) bool

View File

@ -23,7 +23,6 @@ import (
"time"
"github.com/go-gl/glfw/v3.1/glfw"
"github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
)
@ -87,9 +86,6 @@ func initialize() (*opengl.Context, error) {
if err := u.context.Init(); err != nil {
return nil, err
}
if err := graphics.Initialize(u.context); err != nil {
return nil, err
}
return u.context, nil
}
@ -262,6 +258,10 @@ func (u *userInterface) swapBuffers() {
})
}
func (u *userInterface) FinishRendering() error {
return nil
}
func (u *userInterface) setScreenSize(width, height, scale int) bool {
if u.width == width && u.height == height && u.scale == scale {
return false

View File

@ -20,7 +20,6 @@ import (
"strconv"
"github.com/gopherjs/gopherjs/js"
"github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
)
@ -109,6 +108,10 @@ func (u *userInterface) SwapBuffers() error {
return nil
}
func (u *userInterface) FinishRendering() error {
return nil
}
func initialize() (*opengl.Context, error) {
// Do nothing in node.js.
if js.Global.Get("require") != js.Undefined {
@ -116,9 +119,6 @@ func initialize() (*opengl.Context, error) {
if err != nil {
return nil, err
}
if err := graphics.Initialize(c); err != nil {
return nil, err
}
return c, nil
}
@ -226,9 +226,6 @@ func initialize() (*opengl.Context, error) {
if err != nil {
return nil, err
}
if err := graphics.Initialize(c); err != nil {
return nil, err
}
return c, nil
}

View File

@ -17,26 +17,68 @@
package ui
import (
"errors"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
)
func initialize() (*opengl.Context, error) {
// TODO: Implement
return nil, nil
return opengl.NewContext()
}
func Main() error {
return errors.New("ui: don't call this: use RunWithoutMainLoop instead of Run")
}
func Render(chError <-chan error) error {
if chError == nil {
return errors.New("ui: chError must not be nil")
}
// TODO: Check this is called on the rendering thread
chRender <- struct{}{}
worker := glContext.Worker()
loop:
for {
select {
case err := <-chError:
return err
case <-worker.WorkAvailable():
worker.DoWork()
case <-chRenderEnd:
break loop
}
}
return nil
}
type userInterface struct {
width int
height int
scale int
sizeChanged bool
render chan struct{}
renderEnd chan struct{}
}
var (
chRender = make(chan struct{})
chRenderEnd = make(chan struct{})
currentUI = &userInterface{
sizeChanged: true,
render: chRender,
renderEnd: chRenderEnd,
}
)
func CurrentUI() UserInterface {
return nil
return currentUI
}
func (u *userInterface) Start(width, height, scale int, title string) error {
u.width = width
u.height = height
u.scale = scale
// title is ignored?
return nil
}
@ -45,21 +87,46 @@ func (u *userInterface) Terminate() error {
}
func (u *userInterface) Update() (interface{}, error) {
return nil, nil
// TODO: Need lock?
if u.sizeChanged {
u.sizeChanged = false
e := ScreenSizeEvent{
Width: u.width,
Height: u.height,
Scale: u.scale,
ActualScale: u.actualScreenScale(),
}
return e, nil
}
select {
case <-u.render:
return RenderEvent{}, nil
}
}
func (u *userInterface) SwapBuffers() error {
return nil
}
func (u *userInterface) FinishRendering() error {
u.renderEnd <- struct{}{}
return nil
}
func (u *userInterface) SetScreenSize(width, height int) bool {
// TODO: Implement
return false
}
func (u *userInterface) SetScreenScale(scale int) bool {
// TODO: Implement
return false
}
func (u *userInterface) ScreenScale() int {
return 1
return u.scale
}
func (u *userInterface) actualScreenScale() int {
return u.scale
}

View File

@ -15,6 +15,7 @@
package mobile
import (
"errors"
"runtime"
"github.com/hajimehoshi/ebiten"
@ -28,16 +29,6 @@ var chError <-chan error
// Different from ebiten.Run, this invokes only the game loop and not the main (UI) loop.
func Start(f func(*ebiten.Image) error, width, height, scale int, title string) {
chError = ebiten.RunWithoutMainLoop(f, width, height, scale, title)
return
}
func LastErrorString() string {
select {
case err := <-chError:
return err.Error()
default:
return ""
}
}
func SetScreenSize(width, height int) {
@ -48,13 +39,12 @@ func SetScreenScale(scale int) {
ui.CurrentUI().SetScreenScale(scale)
}
func Render() {
func Render() error {
runtime.LockOSThread()
// TODO: Implement this
/*select {
case <-workAvailable:
DoWork()
case <-done:
return
}*/
defer runtime.UnlockOSThread()
if chError == nil {
return errors.New("mobile: chError must not be nil: Start is not called yet?")
}
return ui.Render(chError)
}