diff --git a/gamecontext.go b/gamecontext.go index d83c48ded..75212ffad 100644 --- a/gamecontext.go +++ b/gamecontext.go @@ -77,7 +77,7 @@ func IsGamepadButtonPressed(id int, button GamepadButton) bool { func NewImage(width, height int, filter Filter) (*Image, error) { var img *Image var err error - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { var texture *graphics.Texture var framebuffer *graphics.Framebuffer texture, err = graphics.NewTexture(c, width, height, glFilter(c, filter)) @@ -108,7 +108,7 @@ func NewImage(width, height int, filter Filter) (*Image, error) { func NewImageFromImage(img image.Image, filter Filter) (*Image, error) { var eimg *Image var err error - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { var texture *graphics.Texture var framebuffer *graphics.Framebuffer texture, err = graphics.NewTextureFromImage(c, img, glFilter(c, filter)) diff --git a/genkeys.go b/genkeys.go index 8502d8424..63aac4f4b 100644 --- a/genkeys.go +++ b/genkeys.go @@ -77,7 +77,6 @@ const ebitenKeysTmpl = `{{.License}} package ebiten - import ( "github.com/hajimehoshi/ebiten/internal/ui" ) diff --git a/image.go b/image.go index 707ac2b2d..9c1f3850d 100644 --- a/image.go +++ b/image.go @@ -19,7 +19,6 @@ import ( "fmt" "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl" - "github.com/hajimehoshi/ebiten/internal/ui" "image" "image/color" "math" @@ -53,7 +52,7 @@ func (i *Image) Fill(clr color.Color) (err error) { g := float64(cg) / max b := float64(cb) / max a := float64(ca) / max - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { // TODO: Change to pass color.Color err = i.framebuffer.Fill(c, r, g, b, a) }) @@ -95,7 +94,7 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) { } w, h := image.Size() quads := &textureQuads{parts: parts, width: w, height: h} - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { err = i.framebuffer.DrawTexture(c, image.texture, quads, &options.GeoM, &options.ColorM) }) return @@ -109,7 +108,7 @@ func (i *Image) DrawLine(x0, y0, x1, y1 int, clr color.Color) error { // DrawLines draws lines. func (i *Image) DrawLines(lines Lines) (err error) { i.pixels = nil - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { err = i.framebuffer.DrawLines(c, lines) }) return @@ -133,7 +132,7 @@ func (i *Image) DrawFilledRect(x, y, width, height int, clr color.Color) error { // DrawFilledRects draws filled rectangles on the image. func (i *Image) DrawFilledRects(rects Rects) (err error) { i.pixels = nil - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { err = i.framebuffer.DrawFilledRects(c, rects) }) return @@ -155,7 +154,7 @@ func (i *Image) ColorModel() color.Model { // This method loads pixels from VRAM to system memory if necessary. func (i *Image) At(x, y int) color.Color { if i.pixels == nil { - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { var err error i.pixels, err = i.framebuffer.Pixels(c) if err != nil { @@ -184,7 +183,7 @@ func (i *Image) ReplacePixels(p []uint8) error { return errors.New(fmt.Sprintf("p's length must be %d", l)) } var err error - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { err = i.texture.ReplacePixels(c, p) }) return err diff --git a/internal/ui/input_glfw.go b/internal/ui/input_glfw.go index 772676c32..a69b1a049 100644 --- a/internal/ui/input_glfw.go +++ b/internal/ui/input_glfw.go @@ -21,6 +21,10 @@ import ( "math" ) +func UpdateInput(window *glfw.Window, scale int) error { + return currentInput.update(window, scale) +} + var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{ glfw.MouseButtonLeft: MouseButtonLeft, glfw.MouseButtonRight: MouseButtonRight, diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index 1589241e4..aa0306ed0 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -20,7 +20,11 @@ import ( "github.com/gopherjs/gopherjs/js" ) -func (i *input) keyDown(key int) { +func CurrentInput() *input { + return ¤tInput +} + +func (i *input) KeyDown(key int) { k, ok := keyCodeToKey[key] if !ok { return @@ -28,7 +32,7 @@ func (i *input) keyDown(key int) { i.keyPressed[k] = true } -func (i *input) keyUp(key int) { +func (i *input) KeyUp(key int) { k, ok := keyCodeToKey[key] if !ok { return @@ -36,7 +40,7 @@ func (i *input) keyUp(key int) { i.keyPressed[k] = false } -func (i *input) mouseDown(button int) { +func (i *input) MouseDown(button int) { p := &i.mouseButtonPressed switch button { case 0: @@ -48,7 +52,7 @@ func (i *input) mouseDown(button int) { } } -func (i *input) mouseUp(button int) { +func (i *input) MouseUp(button int) { p := &i.mouseButtonPressed switch button { case 0: @@ -60,11 +64,11 @@ func (i *input) mouseUp(button int) { } } -func (i *input) setMouseCursor(x, y int) { +func (i *input) SetMouseCursor(x, y int) { i.cursorX, i.cursorY = x, y } -func (i *input) updateGamepads() { +func (i *input) UpdateGamepads() { nav := js.Global.Get("navigator") if nav.Get("getGamepads") == js.Undefined { return diff --git a/run.go b/run.go index 68a7f2a38..e6b4f8542 100644 --- a/run.go +++ b/run.go @@ -17,7 +17,6 @@ package ebiten import ( "github.com/hajimehoshi/ebiten/internal/audio" "github.com/hajimehoshi/ebiten/internal/graphics/internal/opengl" - "github.com/hajimehoshi/ebiten/internal/ui" "time" ) @@ -38,14 +37,15 @@ func CurrentFPS() float64 { // but this is not strictly guaranteed. // 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 { - actualScale, err := ui.Start(width, height, scale, title) + ui := currentUI + actualScale, err := ui.start(width, height, scale, title) if err != nil { return err } - defer ui.Terminate() + defer ui.terminate() var graphicsContext *graphicsContext - ui.Use(func(c *opengl.Context) { + useGLContext(func(c *opengl.Context) { graphicsContext, err = newGraphicsContext(c, width, height, actualScale) }) if err != nil { @@ -55,10 +55,10 @@ func Run(f func(*Image) error, width, height, scale int, title string) error { frames := 0 t := time.Now().UnixNano() for { - if err := ui.DoEvents(); err != nil { + if err := ui.doEvents(); err != nil { return err } - if ui.IsClosed() { + if ui.isClosed() { return 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? audio.Update() - ui.SwapBuffers() + ui.swapBuffers() if err != nil { return err } diff --git a/internal/ui/ui_glfw.go b/ui_glfw.go similarity index 78% rename from internal/ui/ui_glfw.go rename to ui_glfw.go index ca2b1d9a5..e746bd5ef 100644 --- a/internal/ui/ui_glfw.go +++ b/ui_glfw.go @@ -14,44 +14,29 @@ // +build !js -package ui +package ebiten import ( "fmt" 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" "time" ) -var current *ui +var currentUI *userInterface -func Use(f func(*opengl.Context)) { +func useGLContext(f func(*opengl.Context)) { ch := make(chan struct{}) - current.funcs <- func() { + currentUI.funcs <- func() { defer close(ch) - f(current.glContext) + f(currentUI.glContext) } <-ch } -func DoEvents() error { - return current.doEvents() -} - -func Terminate() { - current.terminate() -} - -func IsClosed() bool { - return current.isClosed() -} - -func SwapBuffers() { - current.swapBuffers() -} - func init() { runtime.LockOSThread() @@ -69,7 +54,7 @@ func init() { panic(err) } - u := &ui{ + u := &userInterface{ window: window, funcs: make(chan func()), } @@ -85,17 +70,17 @@ func init() { audio.Init() - current = u + currentUI = u } -type ui struct { +type userInterface struct { window *glfw.Window scale int glContext *opengl.Context funcs chan func() } -func Start(width, height, scale int, title string) (actualScale int, err error) { +func (u *userInterface) start(width, height, scale int, title string) (actualScale int, err error) { monitor, err := glfw.GetPrimaryMonitor() if err != nil { return 0, err @@ -108,8 +93,7 @@ func Start(width, height, scale int, title string) (actualScale int, err error) y := (videoMode.Height - height*scale) / 3 ch := make(chan struct{}) - ui := current - window := ui.window + window := u.window window.SetFramebufferSizeCallback(func(w *glfw.Window, width, height int) { close(ch) }) @@ -131,7 +115,7 @@ func Start(width, height, scale int, title string) (actualScale int, err error) } } - ui.scale = scale + u.scale = scale // For retina displays, recalculate the scale with the framebuffer size. windowWidth, _ := window.GetFramebufferSize() @@ -142,16 +126,16 @@ func Start(width, height, scale int, title string) (actualScale int, err error) return actualScale, nil } -func (u *ui) pollEvents() error { +func (u *userInterface) pollEvents() error { glfw.PollEvents() - return currentInput.update(u.window, u.scale) + return ui.UpdateInput(u.window, u.scale) } -func (u *ui) doEvents() error { +func (u *userInterface) doEvents() error { if err := u.pollEvents(); err != nil { return err } - for current.window.GetAttribute(glfw.Focused) == 0 { + for u.window.GetAttribute(glfw.Focused) == 0 { time.Sleep(time.Second / 60) if err := u.pollEvents(); err != nil { return err @@ -160,14 +144,14 @@ func (u *ui) doEvents() error { return nil } -func (u *ui) terminate() { +func (u *userInterface) terminate() { glfw.Terminate() } -func (u *ui) isClosed() bool { +func (u *userInterface) isClosed() bool { return u.window.ShouldClose() } -func (u *ui) swapBuffers() { +func (u *userInterface) swapBuffers() { u.window.SwapBuffers() } diff --git a/internal/ui/ui_js.go b/ui_js.go similarity index 88% rename from internal/ui/ui_js.go rename to ui_js.go index e48c8b85b..ac00dbb07 100644 --- a/internal/ui/ui_js.go +++ b/ui_js.go @@ -14,26 +14,31 @@ // +build js -package ui +package ebiten import ( "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" ) var canvas js.Object var context *opengl.Context +type userInterface struct{} + +var currentUI = &userInterface{} + // TODO: This returns true even when the browser is not active. // The current behavior causes sound noise... func shown() bool { return !js.Global.Get("document").Get("hidden").Bool() } -func Use(f func(*opengl.Context)) { +func useGLContext(f func(*opengl.Context)) { f(context) } @@ -47,24 +52,24 @@ func vsync() { <-ch } -func DoEvents() error { +func (*userInterface) doEvents() error { vsync() for !shown() { vsync() } - currentInput.updateGamepads() + ui.CurrentInput().UpdateGamepads() return nil } -func Terminate() { +func (*userInterface) terminate() { // Do nothing. } -func IsClosed() bool { +func (*userInterface) isClosed() bool { return false } -func SwapBuffers() { +func (*userInterface) swapBuffers() { // Do nothing. } @@ -127,25 +132,25 @@ func init() { canvas.Call("addEventListener", "keydown", func(e js.Object) { e.Call("preventDefault") code := e.Get("keyCode").Int() - currentInput.keyDown(code) + ui.CurrentInput().KeyDown(code) }) canvas.Call("addEventListener", "keyup", func(e js.Object) { e.Call("preventDefault") code := e.Get("keyCode").Int() - currentInput.keyUp(code) + ui.CurrentInput().KeyUp(code) }) // Mouse canvas.Call("addEventListener", "mousedown", func(e js.Object) { e.Call("preventDefault") button := e.Get("button").Int() - currentInput.mouseDown(button) + ui.CurrentInput().MouseDown(button) setMouseCursorFromEvent(e) }) canvas.Call("addEventListener", "mouseup", func(e js.Object) { e.Call("preventDefault") button := e.Get("button").Int() - currentInput.mouseUp(button) + ui.CurrentInput().MouseUp(button) setMouseCursorFromEvent(e) }) canvas.Call("addEventListener", "mousemove", func(e js.Object) { @@ -160,14 +165,14 @@ func init() { // TODO: Need to create indimendent touch functions? canvas.Call("addEventListener", "touchstart", func(e js.Object) { e.Call("preventDefault") - currentInput.mouseDown(0) + ui.CurrentInput().MouseDown(0) touches := e.Get("changedTouches") touch := touches.Index(0) setMouseCursorFromEvent(touch) }) canvas.Call("addEventListener", "touchend", func(e js.Object) { e.Call("preventDefault") - currentInput.mouseUp(0) + ui.CurrentInput().MouseUp(0) touches := e.Get("changedTouches") touch := touches.Index(0) setMouseCursorFromEvent(touch) @@ -193,7 +198,7 @@ func setMouseCursorFromEvent(e js.Object) { x, y := e.Get("clientX").Int(), e.Get("clientY").Int() x -= rect.Get("left").Int() y -= rect.Get("top").Int() - currentInput.setMouseCursor(x/scale, y/scale) + ui.CurrentInput().SetMouseCursor(x/scale, y/scale) } func devicePixelRatio() int { @@ -205,7 +210,7 @@ func devicePixelRatio() int { return ratio } -func Start(width, height, scale int, title string) (actualScale int, err error) { +func (*userInterface) start(width, height, scale int, title string) (actualScale int, err error) { doc := js.Global.Get("document") doc.Set("title", title) actualScale = scale * devicePixelRatio()