Move ui_*.go back to internal/ui again

This commit is contained in:
Hajime Hoshi 2015-01-27 22:02:23 +09:00
parent a1aed91cf9
commit 3964944deb
9 changed files with 123 additions and 68 deletions

View File

@ -15,12 +15,24 @@
package ebiten package ebiten
import ( import (
"github.com/hajimehoshi/ebiten/internal/audio"
"github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/ui" "github.com/hajimehoshi/ebiten/internal/ui"
"image" "image"
) )
var glContext *opengl.Context
func init() {
ui.Init()
ui.ExecOnUIThread(func() {
glContext = opengl.NewContext()
})
audio.Init()
audio.Start()
}
// IsKeyPressed returns a boolean indicating whether key is pressed. // IsKeyPressed returns a boolean indicating whether key is pressed.
func IsKeyPressed(key Key) bool { func IsKeyPressed(key Key) bool {
return ui.IsKeyPressed(ui.Key(key)) return ui.IsKeyPressed(ui.Key(key))

View File

@ -17,8 +17,15 @@ package ebiten
import ( import (
"github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
) )
func useGLContext(f func(*opengl.Context)) {
ui.ExecOnUIThread(func() {
f(glContext)
})
}
func newGraphicsContext(c *opengl.Context, screenWidth, screenHeight, screenScale int) (*graphicsContext, error) { func newGraphicsContext(c *opengl.Context, screenWidth, screenHeight, screenScale int) (*graphicsContext, error) {
f, err := graphics.NewZeroFramebuffer(c, screenWidth*screenScale, screenHeight*screenScale) f, err := graphics.NewZeroFramebuffer(c, screenWidth*screenScale, screenHeight*screenScale)
if err != nil { if err != nil {

View File

@ -50,6 +50,11 @@ func audioProcess(channel int) func(e js.Object) {
} }
func initialize() { func initialize() {
// Do nothing in node.js.
if js.Global.Get("require") != js.Undefined {
return
}
context = js.Global.Get("AudioContext").New() context = js.Global.Get("AudioContext").New()
// TODO: ScriptProcessorNode will be replaced with Audio WebWorker. // TODO: ScriptProcessorNode will be replaced with Audio WebWorker.
// https://developer.mozilla.org/ja/docs/Web/API/ScriptProcessorNode // https://developer.mozilla.org/ja/docs/Web/API/ScriptProcessorNode

View File

@ -40,6 +40,7 @@ func toBytes(l, r []int16) []byte {
} }
func initialize() { func initialize() {
// Creating OpenAL device must be done after initializing UI. I'm not sure the reason.
ch := make(chan struct{}) ch := make(chan struct{})
go func() { go func() {
runtime.LockOSThread() runtime.LockOSThread()

View File

@ -66,7 +66,27 @@ type context struct {
var lastFramebuffer Framebuffer var lastFramebuffer Framebuffer
func NewContext(gl *webgl.Context) *Context { func NewContext() *Context {
var gl *webgl.Context
if js.Global.Get("require") == js.Undefined {
// TODO: Define id?
canvas := js.Global.Get("document").Call("querySelector", "canvas")
var err error
gl, err = webgl.NewContext(canvas, &webgl.ContextAttributes{
Alpha: true,
PremultipliedAlpha: true,
})
if err != nil {
panic(err)
}
} else {
// Use headless-gl for testing.
nodeGl := js.Global.Call("require", "gl")
webglContext := nodeGl.Call("createContext", 16, 16)
gl = &webgl.Context{Object: webglContext}
}
c := &Context{ c := &Context{
Nearest: Filter(gl.NEAREST), Nearest: Filter(gl.NEAREST),
Linear: Filter(gl.LINEAR), Linear: Filter(gl.LINEAR),

View File

@ -21,7 +21,7 @@ import (
"math" "math"
) )
func UpdateInput(window *glfw.Window, scale int) error { func updateInput(window *glfw.Window, scale int) error {
return currentInput.update(window, scale) return currentInput.update(window, scale)
} }

View File

@ -14,30 +14,18 @@
// +build !js // +build !js
package ebiten package ui
import ( import (
"fmt" "fmt"
glfw "github.com/go-gl/glfw3" glfw "github.com/go-gl/glfw3"
"github.com/hajimehoshi/ebiten/internal/audio"
"github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
"runtime" "runtime"
"time" "time"
) )
var currentUI *userInterface var currentUI *userInterface
func useGLContext(f func(*opengl.Context)) { func Init() {
ch := make(chan struct{})
currentUI.funcs <- func() {
defer close(ch)
f(currentUI.glContext)
}
<-ch
}
func init() {
runtime.LockOSThread() runtime.LockOSThread()
glfw.SetErrorCallback(func(err glfw.ErrorCode, desc string) { glfw.SetErrorCallback(func(err glfw.ErrorCode, desc string) {
@ -61,22 +49,47 @@ func init() {
go func() { go func() {
runtime.LockOSThread() runtime.LockOSThread()
u.window.MakeContextCurrent() u.window.MakeContextCurrent()
u.glContext = opengl.NewContext()
glfw.SwapInterval(1) glfw.SwapInterval(1)
for f := range u.funcs { for f := range u.funcs {
f() f()
} }
}() }()
audio.Init()
currentUI = u currentUI = u
} }
func ExecOnUIThread(f func()) {
ch := make(chan struct{})
currentUI.funcs <- func() {
defer close(ch)
f()
}
<-ch
}
func Start(width, height, scale int, title string) (actualScale int, err error) {
return currentUI.start(width, height, scale, title)
}
func Terminate() {
currentUI.terminate()
}
func DoEvents() error {
return currentUI.doEvents()
}
func IsClosed() bool {
return currentUI.isClosed()
}
func SwapBuffers() {
currentUI.swapBuffers()
}
type userInterface struct { type userInterface struct {
window *glfw.Window window *glfw.Window
scale int scale int
glContext *opengl.Context
funcs chan func() funcs chan func()
} }
@ -122,14 +135,12 @@ func (u *userInterface) start(width, height, scale int, title string) (actualSca
windowWidth, _ := window.GetFramebufferSize() windowWidth, _ := window.GetFramebufferSize()
actualScale = windowWidth / width actualScale = windowWidth / width
audio.Start()
return actualScale, nil return actualScale, nil
} }
func (u *userInterface) pollEvents() error { func (u *userInterface) pollEvents() error {
glfw.PollEvents() glfw.PollEvents()
return ui.UpdateInput(u.window, u.scale) return updateInput(u.window, u.scale)
} }
func (u *userInterface) doEvents() error { func (u *userInterface) doEvents() error {

View File

@ -14,19 +14,38 @@
// +build js // +build js
package ebiten package ui
import ( import (
"github.com/gopherjs/gopherjs/js" "github.com/gopherjs/gopherjs/js"
"github.com/gopherjs/webgl"
"github.com/hajimehoshi/ebiten/internal/audio"
"github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
"strconv" "strconv"
) )
func ExecOnUIThread(f func()) {
f()
}
func Start(width, height, scale int, title string) (actualScale int, err error) {
return currentUI.start(width, height, scale, title)
}
func Terminate() {
currentUI.terminate()
}
func DoEvents() error {
return currentUI.doEvents()
}
func IsClosed() bool {
return currentUI.isClosed()
}
func SwapBuffers() {
currentUI.swapBuffers()
}
var canvas js.Object var canvas js.Object
var context *opengl.Context
type userInterface struct{} type userInterface struct{}
@ -38,10 +57,6 @@ func shown() bool {
return !js.Global.Get("document").Get("hidden").Bool() return !js.Global.Get("document").Get("hidden").Bool()
} }
func useGLContext(f func(*opengl.Context)) {
f(context)
}
func vsync() { func vsync() {
ch := make(chan struct{}) ch := make(chan struct{})
// TODO: In iOS8, this is called at every 1/30[sec] frame. // TODO: In iOS8, this is called at every 1/30[sec] frame.
@ -57,7 +72,7 @@ func (*userInterface) doEvents() error {
for !shown() { for !shown() {
vsync() vsync()
} }
ui.CurrentInput().UpdateGamepads() currentInput.UpdateGamepads()
return nil return nil
} }
@ -73,12 +88,9 @@ func (*userInterface) swapBuffers() {
// Do nothing. // Do nothing.
} }
func init() { func Init() {
// Do nothing in node.js.
if js.Global.Get("require") != js.Undefined { if js.Global.Get("require") != js.Undefined {
// Use headless-gl for testing.
nodeGl := js.Global.Call("require", "gl")
webglContext := nodeGl.Call("createContext", 16, 16)
context = opengl.NewContext(&webgl.Context{Object: webglContext})
return return
} }
@ -115,15 +127,6 @@ func init() {
canvasStyle := canvas.Get("style") canvasStyle := canvas.Get("style")
canvasStyle.Set("position", "absolute") canvasStyle.Set("position", "absolute")
webglContext, err := webgl.NewContext(canvas, &webgl.ContextAttributes{
Alpha: true,
PremultipliedAlpha: true,
})
if err != nil {
panic(err)
}
context = opengl.NewContext(webglContext)
// Make the canvas focusable. // Make the canvas focusable.
canvas.Call("setAttribute", "tabindex", 1) canvas.Call("setAttribute", "tabindex", 1)
canvas.Get("style").Set("outline", "none") canvas.Get("style").Set("outline", "none")
@ -132,25 +135,25 @@ func init() {
canvas.Call("addEventListener", "keydown", func(e js.Object) { canvas.Call("addEventListener", "keydown", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
code := e.Get("keyCode").Int() code := e.Get("keyCode").Int()
ui.CurrentInput().KeyDown(code) currentInput.KeyDown(code)
}) })
canvas.Call("addEventListener", "keyup", func(e js.Object) { canvas.Call("addEventListener", "keyup", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
code := e.Get("keyCode").Int() code := e.Get("keyCode").Int()
ui.CurrentInput().KeyUp(code) currentInput.KeyUp(code)
}) })
// Mouse // Mouse
canvas.Call("addEventListener", "mousedown", func(e js.Object) { canvas.Call("addEventListener", "mousedown", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
button := e.Get("button").Int() button := e.Get("button").Int()
ui.CurrentInput().MouseDown(button) currentInput.MouseDown(button)
setMouseCursorFromEvent(e) setMouseCursorFromEvent(e)
}) })
canvas.Call("addEventListener", "mouseup", func(e js.Object) { canvas.Call("addEventListener", "mouseup", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
button := e.Get("button").Int() button := e.Get("button").Int()
ui.CurrentInput().MouseUp(button) currentInput.MouseUp(button)
setMouseCursorFromEvent(e) setMouseCursorFromEvent(e)
}) })
canvas.Call("addEventListener", "mousemove", func(e js.Object) { canvas.Call("addEventListener", "mousemove", func(e js.Object) {
@ -165,14 +168,14 @@ func init() {
// TODO: Need to create indimendent touch functions? // TODO: Need to create indimendent touch functions?
canvas.Call("addEventListener", "touchstart", func(e js.Object) { canvas.Call("addEventListener", "touchstart", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
ui.CurrentInput().MouseDown(0) currentInput.MouseDown(0)
touches := e.Get("changedTouches") touches := e.Get("changedTouches")
touch := touches.Index(0) touch := touches.Index(0)
setMouseCursorFromEvent(touch) setMouseCursorFromEvent(touch)
}) })
canvas.Call("addEventListener", "touchend", func(e js.Object) { canvas.Call("addEventListener", "touchend", func(e js.Object) {
e.Call("preventDefault") e.Call("preventDefault")
ui.CurrentInput().MouseUp(0) currentInput.MouseUp(0)
touches := e.Get("changedTouches") touches := e.Get("changedTouches")
touch := touches.Index(0) touch := touches.Index(0)
setMouseCursorFromEvent(touch) setMouseCursorFromEvent(touch)
@ -188,8 +191,6 @@ func init() {
window.Call("addEventListener", "gamepadconnected", func(e js.Object) { window.Call("addEventListener", "gamepadconnected", func(e js.Object) {
// Do nothing. // Do nothing.
}) })
audio.Init()
} }
func setMouseCursorFromEvent(e js.Object) { func setMouseCursorFromEvent(e js.Object) {
@ -198,7 +199,7 @@ func setMouseCursorFromEvent(e js.Object) {
x, y := e.Get("clientX").Int(), e.Get("clientY").Int() x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
x -= rect.Get("left").Int() x -= rect.Get("left").Int()
y -= rect.Get("top").Int() y -= rect.Get("top").Int()
ui.CurrentInput().SetMouseCursor(x/scale, y/scale) currentInput.SetMouseCursor(x/scale, y/scale)
} }
func devicePixelRatio() int { func devicePixelRatio() int {
@ -229,7 +230,5 @@ func (*userInterface) start(width, height, scale int, title string) (actualScale
canvas.Call("focus") canvas.Call("focus")
audio.Start()
return actualScale, nil return actualScale, nil
} }

12
run.go
View File

@ -17,6 +17,7 @@ package ebiten
import ( import (
"github.com/hajimehoshi/ebiten/internal/audio" "github.com/hajimehoshi/ebiten/internal/audio"
"github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
"time" "time"
) )
@ -37,12 +38,11 @@ func CurrentFPS() float64 {
// but this is not strictly guaranteed. // but this is not strictly guaranteed.
// If you need to care about time, you need to check current time every time f is called. // If you need to care about time, you need to check current time every time f is called.
func Run(f func(*Image) error, width, height, scale int, title string) error { func Run(f func(*Image) error, width, height, scale int, title string) error {
ui := currentUI actualScale, err := ui.Start(width, height, scale, title)
actualScale, err := ui.start(width, height, scale, title)
if err != nil { if err != nil {
return err return err
} }
defer ui.terminate() defer ui.Terminate()
var graphicsContext *graphicsContext var graphicsContext *graphicsContext
useGLContext(func(c *opengl.Context) { useGLContext(func(c *opengl.Context) {
@ -55,10 +55,10 @@ func Run(f func(*Image) error, width, height, scale int, title string) error {
frames := 0 frames := 0
t := time.Now().UnixNano() t := time.Now().UnixNano()
for { for {
if err := ui.doEvents(); err != nil { if err := ui.DoEvents(); err != nil {
return err return err
} }
if ui.isClosed() { if ui.IsClosed() {
return nil return nil
} }
if err := graphicsContext.preUpdate(); err != nil { if err := graphicsContext.preUpdate(); err != nil {
@ -72,7 +72,7 @@ func Run(f func(*Image) error, width, height, scale int, title string) error {
} }
// TODO: I'm not sure this is 'Update'. Is 'Tick' better? // TODO: I'm not sure this is 'Update'. Is 'Tick' better?
audio.Update() audio.Update()
ui.swapBuffers() ui.SwapBuffers()
if err != nil { if err != nil {
return err return err
} }