From 85cbc7e56bf104537a097841a8d7920bc584157c Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 19 Dec 2019 00:03:35 +0900 Subject: [PATCH] Enable to compile Ebiten on js/wasm with Go 1.14 Fixes #1024 --- go.mod | 2 +- go.sum | 4 +- internal/graphicsdriver/opengl/context.go | 6 +-- .../graphicsdriver/opengl/context_desktop.go | 24 +++++++++++ internal/graphicsdriver/opengl/context_js.go | 42 +++++++++++++++---- .../graphicsdriver/opengl/context_mobile.go | 24 +++++++++++ internal/graphicsdriver/opengl/framebuffer.go | 2 +- internal/graphicsdriver/opengl/image.go | 4 +- internal/graphicsdriver/opengl/program.go | 8 ++-- internal/jsutil/equalgo113_js.go | 25 +++++++++++ internal/jsutil/equalgo114_js.go | 25 +++++++++++ internal/uidriver/js/input.go | 9 ++-- internal/uidriver/js/ui.go | 3 +- 13 files changed, 151 insertions(+), 27 deletions(-) create mode 100644 internal/jsutil/equalgo113_js.go create mode 100644 internal/jsutil/equalgo114_js.go diff --git a/go.mod b/go.mod index 418996445..da95995e9 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/hajimehoshi/bitmapfont v1.2.0 github.com/hajimehoshi/go-mp3 v0.2.1 - github.com/hajimehoshi/oto v0.5.3 + github.com/hajimehoshi/oto v0.5.4-0.20191218145825-0644fbe4140c github.com/jakecoffman/cp v0.1.0 github.com/jfreymuth/oggvorbis v1.0.0 github.com/jfreymuth/vorbis v1.0.0 // indirect diff --git a/go.sum b/go.sum index e2d200f57..193c44ee0 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/hajimehoshi/bitmapfont v1.2.0/go.mod h1:h9QrPk6Ktb2neObTlAbma6Ini1xgM github.com/hajimehoshi/go-mp3 v0.2.1 h1:DH4ns3cPv39n3cs8MPcAlWqPeAwLCK8iNgqvg0QBWI8= github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAeX/Rp65DCTE= github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA= -github.com/hajimehoshi/oto v0.5.3 h1:IccIFFUkT0oAr/KdH3LH7USyvI1ZE84HXiGtuCjs3y0= -github.com/hajimehoshi/oto v0.5.3/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= +github.com/hajimehoshi/oto v0.5.4-0.20191218145825-0644fbe4140c h1:Hr7DqgpqLqfeStmF2aTHbWuZGO3/J64Xq2crXC069v8= +github.com/hajimehoshi/oto v0.5.4-0.20191218145825-0644fbe4140c/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= github.com/jakecoffman/cp v0.1.0 h1:sgSYEGUgfwiT447fRjloa2c5b6UyYP+7muR3gQK+Ep0= github.com/jakecoffman/cp v0.1.0/go.mod h1:a3xPx9N8RyFAACD644t2dj/nK4SuLg1v+jL61m2yVo4= github.com/jfreymuth/oggvorbis v1.0.0 h1:aOpiihGrFLXpsh2osOlEvTcg5/aluzGQeC7m3uYWOZ0= diff --git a/internal/graphicsdriver/opengl/context.go b/internal/graphicsdriver/opengl/context.go index de919f2c0..08a06841f 100644 --- a/internal/graphicsdriver/opengl/context.go +++ b/internal/graphicsdriver/opengl/context.go @@ -60,7 +60,7 @@ type context struct { } func (c *context) bindTexture(t textureNative) { - if c.lastTexture == t { + if c.lastTexture.equal(t) { return } c.bindTextureImpl(t) @@ -68,7 +68,7 @@ func (c *context) bindTexture(t textureNative) { } func (c *context) bindFramebuffer(f framebufferNative) { - if c.lastFramebuffer == f { + if c.lastFramebuffer.equal(f) { return } c.bindFramebufferImpl(f) @@ -86,7 +86,7 @@ func (c *context) setViewport(f *framebuffer) { // glViewport must be called at least at every frame on iOS. // As the screen framebuffer is the last render target, next SetViewport should be // the first call at a frame. - if f.native == c.screenFramebuffer { + if f.native.equal(c.screenFramebuffer) { c.lastViewportWidth = 0 c.lastViewportHeight = 0 } else { diff --git a/internal/graphicsdriver/opengl/context_desktop.go b/internal/graphicsdriver/opengl/context_desktop.go index 1e6260870..78e16c0f2 100644 --- a/internal/graphicsdriver/opengl/context_desktop.go +++ b/internal/graphicsdriver/opengl/context_desktop.go @@ -35,6 +35,30 @@ type ( buffer uint32 ) +func (t textureNative) equal(rhs textureNative) bool { + return t == rhs +} + +func (f framebufferNative) equal(rhs framebufferNative) bool { + return f == rhs +} + +func (s shader) equal(rhs shader) bool { + return s == rhs +} + +func (b buffer) equal(rhs buffer) bool { + return b == rhs +} + +func (u uniformLocation) equal(rhs uniformLocation) bool { + return u == rhs +} + +func (p program) equal(rhs program) bool { + return p == rhs +} + var InvalidTexture textureNative type ( diff --git a/internal/graphicsdriver/opengl/context_js.go b/internal/graphicsdriver/opengl/context_js.go index 096f32669..ac8ee28da 100644 --- a/internal/graphicsdriver/opengl/context_js.go +++ b/internal/graphicsdriver/opengl/context_js.go @@ -41,6 +41,30 @@ type ( } ) +func (t textureNative) equal(rhs textureNative) bool { + return jsutil.Equal(js.Value(t), js.Value(rhs)) +} + +func (f framebufferNative) equal(rhs framebufferNative) bool { + return jsutil.Equal(js.Value(f), js.Value(rhs)) +} + +func (s shader) equal(rhs shader) bool { + return jsutil.Equal(js.Value(s), js.Value(rhs)) +} + +func (b buffer) equal(rhs buffer) bool { + return jsutil.Equal(js.Value(b), js.Value(rhs)) +} + +func (u uniformLocation) equal(rhs uniformLocation) bool { + return jsutil.Equal(js.Value(u), js.Value(rhs)) +} + +func (p program) equal(rhs program) bool { + return jsutil.Equal(p.value, rhs.value) && p.id == rhs.id +} + var InvalidTexture = textureNative(js.Null()) func getProgramID(p program) programID { @@ -96,11 +120,11 @@ type contextImpl struct { } func (c *context) ensureGL() { - if c.gl != (js.Value{}) { + if !jsutil.Equal(c.gl, js.Value{}) { return } - if js.Global().Get("WebGLRenderingContext") == js.Undefined() { + if jsutil.Equal(js.Global().Get("WebGLRenderingContext"), js.Undefined()) { panic("opengl: WebGL is not supported") } // TODO: Define id? @@ -109,9 +133,9 @@ func (c *context) ensureGL() { attr.Set("alpha", true) attr.Set("premultipliedAlpha", true) gl := canvas.Call("getContext", "webgl", attr) - if gl == js.Null() { + if jsutil.Equal(gl, js.Null()) { gl = canvas.Call("getContext", "experimental-webgl", attr) - if gl == js.Null() { + if jsutil.Equal(gl, js.Null()) { panic("opengl: getContext failed") } } @@ -156,7 +180,7 @@ func (c *context) newTexture(width, height int) (textureNative, error) { c.ensureGL() gl := c.gl t := gl.Call("createTexture") - if t == js.Null() { + if jsutil.Equal(t, js.Null()) { return textureNative(js.Null()), errors.New("opengl: glGenTexture failed") } gl.Call("pixelStorei", unpackAlignment, 4) @@ -209,7 +233,7 @@ func (c *context) deleteTexture(t textureNative) { if !gl.Call("isTexture", js.Value(t)).Bool() { return } - if c.lastTexture == t { + if c.lastTexture.equal(t) { c.lastTexture = textureNative(js.Null()) } gl.Call("deleteTexture", js.Value(t)) @@ -262,7 +286,7 @@ func (c *context) deleteFramebuffer(f framebufferNative) { // If a framebuffer to be deleted is bound, a newly bound framebuffer // will be a default framebuffer. // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml - if c.lastFramebuffer == f { + if c.lastFramebuffer.equal(f) { c.lastFramebuffer = framebufferNative(js.Null()) c.lastViewportWidth = 0 c.lastViewportHeight = 0 @@ -274,7 +298,7 @@ func (c *context) newShader(shaderType shaderType, source string) (shader, error c.ensureGL() gl := c.gl s := gl.Call("createShader", int(shaderType)) - if s == js.Null() { + if jsutil.Equal(s, js.Null()) { return shader(js.Null()), fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType) } @@ -298,7 +322,7 @@ func (c *context) newProgram(shaders []shader, attributes []string) (program, er c.ensureGL() gl := c.gl v := gl.Call("createProgram") - if v == js.Null() { + if jsutil.Equal(v, js.Null()) { return program{}, errors.New("opengl: glCreateProgram failed") } diff --git a/internal/graphicsdriver/opengl/context_mobile.go b/internal/graphicsdriver/opengl/context_mobile.go index e918e6a1a..51bc5f77d 100644 --- a/internal/graphicsdriver/opengl/context_mobile.go +++ b/internal/graphicsdriver/opengl/context_mobile.go @@ -33,6 +33,26 @@ type ( buffer mgl.Buffer ) +func (t textureNative) equal(rhs textureNative) bool { + return t == rhs +} + +func (f framebufferNative) equal(rhs framebufferNative) bool { + return f == rhs +} + +func (s shader) equal(rhs shader) bool { + return s == rhs +} + +func (b buffer) equal(rhs buffer) bool { + return b == rhs +} + +func (p program) equal(rhs program) bool { + return p == rhs +} + var InvalidTexture textureNative type ( @@ -40,6 +60,10 @@ type ( attribLocation mgl.Attrib ) +func (u uniformLocation) equal(rhs uniformLocation) bool { + return u == rhs +} + type programID uint32 var ( diff --git a/internal/graphicsdriver/opengl/framebuffer.go b/internal/graphicsdriver/opengl/framebuffer.go index b19f7becb..122464fcd 100644 --- a/internal/graphicsdriver/opengl/framebuffer.go +++ b/internal/graphicsdriver/opengl/framebuffer.go @@ -45,7 +45,7 @@ func newScreenFramebuffer(context *context, width, height int) *framebuffer { } func (f *framebuffer) delete(context *context) { - if f.native != context.getScreenFramebuffer() { + if !f.native.equal(context.getScreenFramebuffer()) { context.deleteFramebuffer(f.native) } } diff --git a/internal/graphicsdriver/opengl/image.go b/internal/graphicsdriver/opengl/image.go index 5119857c9..5e07bc450 100644 --- a/internal/graphicsdriver/opengl/image.go +++ b/internal/graphicsdriver/opengl/image.go @@ -34,13 +34,13 @@ func (i *Image) IsInvalidated() bool { } func (i *Image) Dispose() { - if i.pbo != *new(buffer) { + if !i.pbo.equal(*new(buffer)) { i.driver.context.deleteBuffer(i.pbo) } if i.framebuffer != nil { i.framebuffer.delete(&i.driver.context) } - if i.textureNative != *new(textureNative) { + if !i.textureNative.equal(*new(textureNative)) { i.driver.context.deleteTexture(i.textureNative) } } diff --git a/internal/graphicsdriver/opengl/program.go b/internal/graphicsdriver/opengl/program.go index 458ea2c7e..5c9711a67 100644 --- a/internal/graphicsdriver/opengl/program.go +++ b/internal/graphicsdriver/opengl/program.go @@ -183,10 +183,10 @@ func (s *openGLState) reset(context *context) error { // On browsers (at least Chrome), buffers are already detached from the context // and must not be deleted by DeleteBuffer. if !web.IsBrowser() { - if s.arrayBuffer != zeroBuffer { + if !s.arrayBuffer.equal(zeroBuffer) { context.deleteBuffer(s.arrayBuffer) } - if s.elementArrayBuffer != zeroBuffer { + if !s.elementArrayBuffer.equal(zeroBuffer) { context.deleteBuffer(s.elementArrayBuffer) } } @@ -278,9 +278,9 @@ func (d *Driver) useProgram(mode driver.CompositeMode, colorM *affine.ColorM, fi filter: filter, address: address, }] - if d.state.lastProgram != program { + if !d.state.lastProgram.equal(program) { d.context.useProgram(program) - if d.state.lastProgram == zeroProgram { + if d.state.lastProgram.equal(zeroProgram) { theArrayBufferLayout.enable(&d.context, program) d.context.bindBuffer(arrayBuffer, d.state.arrayBuffer) d.context.bindBuffer(elementArrayBuffer, d.state.elementArrayBuffer) diff --git a/internal/jsutil/equalgo113_js.go b/internal/jsutil/equalgo113_js.go new file mode 100644 index 000000000..61fb55b1e --- /dev/null +++ b/internal/jsutil/equalgo113_js.go @@ -0,0 +1,25 @@ +// Copyright 2019 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !go1.14 + +package jsutil + +import ( + "syscall/js" +) + +func Equal(a, b js.Value) bool { + return a == b +} diff --git a/internal/jsutil/equalgo114_js.go b/internal/jsutil/equalgo114_js.go new file mode 100644 index 000000000..b094f582a --- /dev/null +++ b/internal/jsutil/equalgo114_js.go @@ -0,0 +1,25 @@ +// Copyright 2019 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build go1.14 + +package jsutil + +import ( + "syscall/js" +) + +func Equal(a, b js.Value) bool { + return a.Equal(b) +} diff --git a/internal/uidriver/js/input.go b/internal/uidriver/js/input.go index e9afab6d4..2976f4f8e 100644 --- a/internal/uidriver/js/input.go +++ b/internal/uidriver/js/input.go @@ -21,6 +21,7 @@ import ( "unicode" "github.com/hajimehoshi/ebiten/internal/driver" + "github.com/hajimehoshi/ebiten/internal/jsutil" ) type pos struct { @@ -220,7 +221,7 @@ func (i *Input) setMouseCursor(x, y int) { func (i *Input) UpdateGamepads() { nav := js.Global().Get("navigator") - if nav.Get("getGamepads") == js.Undefined() { + if jsutil.Equal(nav.Get("getGamepads"), js.Undefined()) { return } gamepads := nav.Call("getGamepads") @@ -228,7 +229,7 @@ func (i *Input) UpdateGamepads() { for id := 0; id < l; id++ { i.gamepads[id].valid = false gamepad := gamepads.Index(id) - if gamepad == js.Undefined() || gamepad == js.Null() { + if jsutil.Equal(gamepad, js.Undefined()) || jsutil.Equal(gamepad, js.Null()) { continue } i.gamepads[id].valid = true @@ -261,7 +262,7 @@ func (i *Input) Update(e js.Value) { switch e.Get("type").String() { case "keydown": c := e.Get("code") - if c == js.Undefined() { + if jsutil.Equal(c, js.Undefined()) { code := e.Get("keyCode").Int() if keyCodeToKeyEdge[code] == driver.KeyUp || keyCodeToKeyEdge[code] == driver.KeyDown || @@ -289,7 +290,7 @@ func (i *Input) Update(e js.Value) { i.runeBuffer = append(i.runeBuffer, r) } case "keyup": - if e.Get("code") == js.Undefined() { + if jsutil.Equal(e.Get("code"), js.Undefined()) { // Assume that UA is Edge. code := e.Get("keyCode").Int() i.keyUpEdge(code) diff --git a/internal/uidriver/js/ui.go b/internal/uidriver/js/ui.go index d483915c7..19ff0cd91 100644 --- a/internal/uidriver/js/ui.go +++ b/internal/uidriver/js/ui.go @@ -26,6 +26,7 @@ import ( "github.com/hajimehoshi/ebiten/internal/devicescale" "github.com/hajimehoshi/ebiten/internal/driver" "github.com/hajimehoshi/ebiten/internal/hooks" + "github.com/hajimehoshi/ebiten/internal/jsutil" ) type UserInterface struct { @@ -247,7 +248,7 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error { } func init() { - if document.Get("body") == js.Null() { + if jsutil.Equal(document.Get("body"), js.Null()) { ch := make(chan struct{}) window.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} { close(ch)