mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
opengl: Remove Init (except for mobile)
This commit is contained in:
parent
16ada03928
commit
4090258904
44
internal/mainthread/mainthread.go
Normal file
44
internal/mainthread/mainthread.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package mainthread
|
||||
|
||||
var funcs = make(chan func())
|
||||
|
||||
// Loop starts the main-thread loop.
|
||||
//
|
||||
// Loop must be called on the main thread.
|
||||
func Loop(ch <-chan error) error {
|
||||
for {
|
||||
select {
|
||||
case f := <-funcs:
|
||||
f()
|
||||
case err := <-ch:
|
||||
// ch returns a value not only when an error occur but also it is closed.
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run calls f on the main thread.
|
||||
func Run(f func() error) error {
|
||||
ch := make(chan struct{})
|
||||
var err error
|
||||
funcs <- func() {
|
||||
err = f()
|
||||
close(ch)
|
||||
}
|
||||
<-ch
|
||||
return err
|
||||
}
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/mainthread"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -74,22 +75,15 @@ func init() {
|
||||
}
|
||||
|
||||
type context struct {
|
||||
init bool
|
||||
runOnMainThread func(func() error) error
|
||||
init bool
|
||||
}
|
||||
|
||||
func Init(runOnMainThread func(func() error) error) {
|
||||
c := &Context{}
|
||||
c.runOnMainThread = runOnMainThread
|
||||
theContext = c
|
||||
}
|
||||
|
||||
func (c *Context) runOnContextThread(f func() error) error {
|
||||
return c.runOnMainThread(f)
|
||||
func init() {
|
||||
theContext = &Context{}
|
||||
}
|
||||
|
||||
func (c *Context) reset() error {
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
if c.init {
|
||||
return nil
|
||||
}
|
||||
@ -108,12 +102,12 @@ func (c *Context) reset() error {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
c.lastCompositeMode = graphics.CompositeModeUnknown
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.Enable(gl.BLEND)
|
||||
return nil
|
||||
})
|
||||
c.BlendFunc(graphics.CompositeModeSourceOver)
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
f := int32(0)
|
||||
gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f)
|
||||
c.screenFramebuffer = framebufferNative(f)
|
||||
@ -123,7 +117,7 @@ func (c *Context) reset() error {
|
||||
}
|
||||
|
||||
func (c *Context) BlendFunc(mode graphics.CompositeMode) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
if c.lastCompositeMode == mode {
|
||||
return nil
|
||||
}
|
||||
@ -137,7 +131,7 @@ func (c *Context) BlendFunc(mode graphics.CompositeMode) {
|
||||
|
||||
func (c *Context) newTexture(width, height int) (textureNative, error) {
|
||||
var texture textureNative
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
var t uint32
|
||||
gl.GenTextures(1, &t)
|
||||
// TODO: Use gl.IsTexture
|
||||
@ -151,7 +145,7 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
|
||||
return 0, err
|
||||
}
|
||||
c.bindTexture(texture)
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
@ -163,7 +157,7 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
|
||||
}
|
||||
|
||||
func (c *Context) bindFramebufferImpl(f framebufferNative) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.BindFramebufferEXT(gl.FRAMEBUFFER, uint32(f))
|
||||
return nil
|
||||
})
|
||||
@ -171,12 +165,12 @@ func (c *Context) bindFramebufferImpl(f framebufferNative) {
|
||||
|
||||
func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte, error) {
|
||||
var pixels []byte
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.Flush()
|
||||
return nil
|
||||
})
|
||||
c.bindFramebuffer(f.native)
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
pixels = make([]byte, 4*width*height)
|
||||
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels))
|
||||
if e := gl.GetError(); e != gl.NO_ERROR {
|
||||
@ -191,14 +185,14 @@ func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
|
||||
}
|
||||
|
||||
func (c *Context) bindTextureImpl(t textureNative) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.BindTexture(gl.TEXTURE_2D, uint32(t))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) deleteTexture(t textureNative) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
tt := uint32(t)
|
||||
if !gl.IsTexture(tt) {
|
||||
return nil
|
||||
@ -213,7 +207,7 @@ func (c *Context) deleteTexture(t textureNative) {
|
||||
|
||||
func (c *Context) isTexture(t textureNative) bool {
|
||||
r := false
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
r = gl.IsTexture(uint32(t))
|
||||
return nil
|
||||
})
|
||||
@ -222,7 +216,7 @@ func (c *Context) isTexture(t textureNative) bool {
|
||||
|
||||
func (c *Context) texSubImage2D(t textureNative, p []byte, x, y, width, height int) {
|
||||
c.bindTexture(t)
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.TexSubImage2D(gl.TEXTURE_2D, 0, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p))
|
||||
return nil
|
||||
})
|
||||
@ -235,7 +229,7 @@ func (c *Context) BeforeSwapping() {
|
||||
func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, error) {
|
||||
var framebuffer framebufferNative
|
||||
var f uint32
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
gl.GenFramebuffersEXT(1, &f)
|
||||
// TODO: Use gl.IsFramebuffer
|
||||
if f <= 0 {
|
||||
@ -246,7 +240,7 @@ func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, erro
|
||||
return 0, err
|
||||
}
|
||||
c.bindFramebuffer(framebufferNative(f))
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
gl.FramebufferTexture2DEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(texture), 0)
|
||||
s := gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER)
|
||||
if s != gl.FRAMEBUFFER_COMPLETE {
|
||||
@ -267,14 +261,14 @@ func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, erro
|
||||
}
|
||||
|
||||
func (c *Context) setViewportImpl(width, height int) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.Viewport(0, 0, int32(width), int32(height))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) deleteFramebuffer(f framebufferNative) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
ff := uint32(f)
|
||||
if !gl.IsFramebufferEXT(ff) {
|
||||
return nil
|
||||
@ -291,7 +285,7 @@ func (c *Context) deleteFramebuffer(f framebufferNative) {
|
||||
|
||||
func (c *Context) newShader(shaderType shaderType, source string) (shader, error) {
|
||||
var sh shader
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
s := gl.CreateShader(uint32(shaderType))
|
||||
if s == 0 {
|
||||
return fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
|
||||
@ -321,7 +315,7 @@ func (c *Context) newShader(shaderType shaderType, source string) (shader, error
|
||||
}
|
||||
|
||||
func (c *Context) deleteShader(s shader) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.DeleteShader(uint32(s))
|
||||
return nil
|
||||
})
|
||||
@ -329,7 +323,7 @@ func (c *Context) deleteShader(s shader) {
|
||||
|
||||
func (c *Context) newProgram(shaders []shader) (program, error) {
|
||||
var pr program
|
||||
if err := c.runOnContextThread(func() error {
|
||||
if err := mainthread.Run(func() error {
|
||||
p := gl.CreateProgram()
|
||||
if p == 0 {
|
||||
return errors.New("opengl: glCreateProgram failed")
|
||||
@ -353,14 +347,14 @@ func (c *Context) newProgram(shaders []shader) (program, error) {
|
||||
}
|
||||
|
||||
func (c *Context) useProgram(p program) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.UseProgram(uint32(p))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) deleteProgram(p program) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
if !gl.IsProgram(uint32(p)) {
|
||||
return nil
|
||||
}
|
||||
@ -380,7 +374,7 @@ func (c *Context) getUniformLocationImpl(p program, location string) uniformLoca
|
||||
}
|
||||
|
||||
func (c *Context) uniformInt(p program, location string, v int) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := int32(c.locationCache.GetUniformLocation(c, p, location))
|
||||
gl.Uniform1i(l, int32(v))
|
||||
return nil
|
||||
@ -388,7 +382,7 @@ func (c *Context) uniformInt(p program, location string, v int) {
|
||||
}
|
||||
|
||||
func (c *Context) uniformFloat(p program, location string, v float32) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := int32(c.locationCache.GetUniformLocation(c, p, location))
|
||||
gl.Uniform1f(l, v)
|
||||
return nil
|
||||
@ -396,7 +390,7 @@ func (c *Context) uniformFloat(p program, location string, v float32) {
|
||||
}
|
||||
|
||||
func (c *Context) uniformFloats(p program, location string, v []float32) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := int32(c.locationCache.GetUniformLocation(c, p, location))
|
||||
switch len(v) {
|
||||
case 2:
|
||||
@ -423,7 +417,7 @@ func (c *Context) getAttribLocationImpl(p program, location string) attribLocati
|
||||
}
|
||||
|
||||
func (c *Context) vertexAttribPointer(p program, location string, size int, dataType DataType, stride int, offset int) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.VertexAttribPointer(uint32(l), int32(size), uint32(dataType), false, int32(stride), gl.PtrOffset(offset))
|
||||
return nil
|
||||
@ -431,7 +425,7 @@ func (c *Context) vertexAttribPointer(p program, location string, size int, data
|
||||
}
|
||||
|
||||
func (c *Context) enableVertexAttribArray(p program, location string) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.EnableVertexAttribArray(uint32(l))
|
||||
return nil
|
||||
@ -439,7 +433,7 @@ func (c *Context) enableVertexAttribArray(p program, location string) {
|
||||
}
|
||||
|
||||
func (c *Context) disableVertexAttribArray(p program, location string) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.DisableVertexAttribArray(uint32(l))
|
||||
return nil
|
||||
@ -448,7 +442,7 @@ func (c *Context) disableVertexAttribArray(p program, location string) {
|
||||
|
||||
func (c *Context) newArrayBuffer(size int) buffer {
|
||||
var bf buffer
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
var b uint32
|
||||
gl.GenBuffers(1, &b)
|
||||
gl.BindBuffer(uint32(arrayBuffer), b)
|
||||
@ -461,7 +455,7 @@ func (c *Context) newArrayBuffer(size int) buffer {
|
||||
|
||||
func (c *Context) newElementArrayBuffer(size int) buffer {
|
||||
var bf buffer
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
var b uint32
|
||||
gl.GenBuffers(1, &b)
|
||||
gl.BindBuffer(uint32(elementArrayBuffer), b)
|
||||
@ -473,28 +467,28 @@ func (c *Context) newElementArrayBuffer(size int) buffer {
|
||||
}
|
||||
|
||||
func (c *Context) bindBuffer(bufferType bufferType, b buffer) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.BindBuffer(uint32(bufferType), uint32(b))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) arrayBufferSubData(data []float32) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.BufferSubData(uint32(arrayBuffer), 0, len(data)*4, gl.Ptr(data))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) elementArrayBufferSubData(data []uint16) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.BufferSubData(uint32(elementArrayBuffer), 0, len(data)*2, gl.Ptr(data))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) deleteBuffer(b buffer) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
bb := uint32(b)
|
||||
gl.DeleteBuffers(1, &bb)
|
||||
return nil
|
||||
@ -502,7 +496,7 @@ func (c *Context) deleteBuffer(b buffer) {
|
||||
}
|
||||
|
||||
func (c *Context) DrawElements(len int, offsetInBytes int) {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.DrawElements(gl.TRIANGLES, int32(len), gl.UNSIGNED_SHORT, gl.PtrOffset(offsetInBytes))
|
||||
return nil
|
||||
})
|
||||
@ -510,7 +504,7 @@ func (c *Context) DrawElements(len int, offsetInBytes int) {
|
||||
|
||||
func (c *Context) maxTextureSizeImpl() int {
|
||||
size := 0
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
s := int32(0)
|
||||
gl.GetIntegerv(gl.MAX_TEXTURE_SIZE, &s)
|
||||
size = int(s)
|
||||
@ -520,7 +514,7 @@ func (c *Context) maxTextureSizeImpl() int {
|
||||
}
|
||||
|
||||
func (c *Context) Flush() {
|
||||
_ = c.runOnContextThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
gl.Flush()
|
||||
return nil
|
||||
})
|
||||
|
@ -119,11 +119,18 @@ type context struct {
|
||||
lastProgramID programID
|
||||
}
|
||||
|
||||
func Init() error {
|
||||
if js.Global().Get("WebGLRenderingContext") == js.Undefined() {
|
||||
return fmt.Errorf("opengl: WebGL is not supported")
|
||||
func init() {
|
||||
theContext = &Context{}
|
||||
}
|
||||
|
||||
func (c *Context) ensureGL() {
|
||||
if c.gl != (js.Value{}) {
|
||||
return
|
||||
}
|
||||
|
||||
if js.Global().Get("WebGLRenderingContext") == js.Undefined() {
|
||||
panic("opengl: WebGL is not supported")
|
||||
}
|
||||
// TODO: Define id?
|
||||
canvas := js.Global().Get("document").Call("querySelector", "canvas")
|
||||
attr := js.Global().Get("Object").New()
|
||||
@ -133,18 +140,15 @@ func Init() error {
|
||||
if gl == js.Null() {
|
||||
gl = canvas.Call("getContext", "experimental-webgl", attr)
|
||||
if gl == js.Null() {
|
||||
return fmt.Errorf("opengl: getContext failed")
|
||||
panic("opengl: getContext failed")
|
||||
}
|
||||
}
|
||||
c := &Context{}
|
||||
|
||||
c.gl = gl
|
||||
|
||||
// Getting an extension might fail after the context is lost, so
|
||||
// it is required to get the extension here.
|
||||
c.loseContext = gl.Call("getExtension", "WEBGL_lose_context")
|
||||
|
||||
theContext = c
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) reset() error {
|
||||
@ -154,6 +158,8 @@ func (c *Context) reset() error {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
c.lastCompositeMode = graphics.CompositeModeUnknown
|
||||
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("enable", blend)
|
||||
c.BlendFunc(graphics.CompositeModeSourceOver)
|
||||
@ -169,11 +175,13 @@ func (c *Context) BlendFunc(mode graphics.CompositeMode) {
|
||||
c.lastCompositeMode = mode
|
||||
s, d := mode.Operations()
|
||||
s2, d2 := convertOperation(s), convertOperation(d)
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("blendFunc", int(s2), int(d2))
|
||||
}
|
||||
|
||||
func (c *Context) newTexture(width, height int) (textureNative, error) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
t := gl.Call("createTexture")
|
||||
if t == js.Null() {
|
||||
@ -200,11 +208,13 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
|
||||
}
|
||||
|
||||
func (c *Context) bindFramebufferImpl(f framebufferNative) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("bindFramebuffer", framebuffer_, js.Value(f))
|
||||
}
|
||||
|
||||
func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte, error) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
|
||||
c.bindFramebuffer(f.native)
|
||||
@ -221,11 +231,13 @@ func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
|
||||
}
|
||||
|
||||
func (c *Context) bindTextureImpl(t textureNative) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("bindTexture", texture2d, js.Value(t))
|
||||
}
|
||||
|
||||
func (c *Context) deleteTexture(t textureNative) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
if !gl.Call("isTexture", js.Value(t)).Bool() {
|
||||
return
|
||||
@ -237,12 +249,14 @@ func (c *Context) deleteTexture(t textureNative) {
|
||||
}
|
||||
|
||||
func (c *Context) isTexture(t textureNative) bool {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
return gl.Call("isTexture", js.Value(t)).Bool()
|
||||
}
|
||||
|
||||
func (c *Context) texSubImage2D(t textureNative, pixels []byte, x, y, width, height int) {
|
||||
c.bindTexture(t)
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
@ -253,6 +267,7 @@ func (c *Context) texSubImage2D(t textureNative, pixels []byte, x, y, width, hei
|
||||
}
|
||||
|
||||
func (c *Context) newFramebuffer(t textureNative) (framebufferNative, error) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
f := gl.Call("createFramebuffer")
|
||||
c.bindFramebuffer(framebufferNative(f))
|
||||
@ -266,11 +281,13 @@ func (c *Context) newFramebuffer(t textureNative) (framebufferNative, error) {
|
||||
}
|
||||
|
||||
func (c *Context) setViewportImpl(width, height int) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("viewport", 0, 0, width, height)
|
||||
}
|
||||
|
||||
func (c *Context) deleteFramebuffer(f framebufferNative) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
if !gl.Call("isFramebuffer", js.Value(f)).Bool() {
|
||||
return
|
||||
@ -287,6 +304,7 @@ func (c *Context) deleteFramebuffer(f framebufferNative) {
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -304,11 +322,13 @@ func (c *Context) newShader(shaderType shaderType, source string) (shader, error
|
||||
}
|
||||
|
||||
func (c *Context) deleteShader(s shader) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("deleteShader", js.Value(s))
|
||||
}
|
||||
|
||||
func (c *Context) newProgram(shaders []shader) (program, error) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
v := gl.Call("createProgram")
|
||||
if v == js.Null() {
|
||||
@ -332,11 +352,13 @@ func (c *Context) newProgram(shaders []shader) (program, error) {
|
||||
}
|
||||
|
||||
func (c *Context) useProgram(p program) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("useProgram", p.value)
|
||||
}
|
||||
|
||||
func (c *Context) deleteProgram(p program) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
if !gl.Call("isProgram", p.value).Bool() {
|
||||
return
|
||||
@ -345,17 +367,20 @@ func (c *Context) deleteProgram(p program) {
|
||||
}
|
||||
|
||||
func (c *Context) getUniformLocationImpl(p program, location string) uniformLocation {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
return uniformLocation(gl.Call("getUniformLocation", p.value, location))
|
||||
}
|
||||
|
||||
func (c *Context) uniformInt(p program, location string, v int) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
gl.Call("uniform1i", js.Value(l), v)
|
||||
}
|
||||
|
||||
func (c *Context) uniformFloat(p program, location string, v float32) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
gl.Call("uniform1f", js.Value(l), v)
|
||||
@ -366,6 +391,7 @@ var (
|
||||
)
|
||||
|
||||
func (c *Context) uniformFloats(p program, location string, v []float32) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
switch len(v) {
|
||||
@ -383,29 +409,34 @@ func (c *Context) uniformFloats(p program, location string, v []float32) {
|
||||
}
|
||||
|
||||
func (c *Context) getAttribLocationImpl(p program, location string) attribLocation {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
return attribLocation(gl.Call("getAttribLocation", p.value, location).Int())
|
||||
}
|
||||
|
||||
func (c *Context) vertexAttribPointer(p program, location string, size int, dataType DataType, stride int, offset int) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.Call("vertexAttribPointer", int(l), size, int(dataType), false, stride, offset)
|
||||
}
|
||||
|
||||
func (c *Context) enableVertexAttribArray(p program, location string) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.Call("enableVertexAttribArray", int(l))
|
||||
}
|
||||
|
||||
func (c *Context) disableVertexAttribArray(p program, location string) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
l := c.locationCache.GetAttribLocation(c, p, location)
|
||||
gl.Call("disableVertexAttribArray", int(l))
|
||||
}
|
||||
|
||||
func (c *Context) newArrayBuffer(size int) buffer {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
b := gl.Call("createBuffer")
|
||||
gl.Call("bindBuffer", int(arrayBuffer), js.Value(b))
|
||||
@ -414,6 +445,7 @@ func (c *Context) newArrayBuffer(size int) buffer {
|
||||
}
|
||||
|
||||
func (c *Context) newElementArrayBuffer(size int) buffer {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
b := gl.Call("createBuffer")
|
||||
gl.Call("bindBuffer", int(elementArrayBuffer), js.Value(b))
|
||||
@ -422,11 +454,13 @@ func (c *Context) newElementArrayBuffer(size int) buffer {
|
||||
}
|
||||
|
||||
func (c *Context) bindBuffer(bufferType bufferType, b buffer) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("bindBuffer", int(bufferType), js.Value(b))
|
||||
}
|
||||
|
||||
func (c *Context) arrayBufferSubData(data []float32) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
arr := js.TypedArrayOf(data)
|
||||
gl.Call("bufferSubData", int(arrayBuffer), 0, arr)
|
||||
@ -434,6 +468,7 @@ func (c *Context) arrayBufferSubData(data []float32) {
|
||||
}
|
||||
|
||||
func (c *Context) elementArrayBufferSubData(data []uint16) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
arr := js.TypedArrayOf(data)
|
||||
gl.Call("bufferSubData", int(elementArrayBuffer), 0, arr)
|
||||
@ -441,26 +476,31 @@ func (c *Context) elementArrayBufferSubData(data []uint16) {
|
||||
}
|
||||
|
||||
func (c *Context) deleteBuffer(b buffer) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("deleteBuffer", js.Value(b))
|
||||
}
|
||||
|
||||
func (c *Context) DrawElements(len int, offsetInBytes int) {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("drawElements", triangles, len, unsignedShort, offsetInBytes)
|
||||
}
|
||||
|
||||
func (c *Context) maxTextureSizeImpl() int {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
return gl.Call("getParameter", maxTextureSize).Int()
|
||||
}
|
||||
|
||||
func (c *Context) Flush() {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
gl.Call("flush")
|
||||
}
|
||||
|
||||
func (c *Context) IsContextLost() bool {
|
||||
c.ensureGL()
|
||||
gl := c.gl
|
||||
return gl.Call("isContextLost").Bool()
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
||||
"github.com/hajimehoshi/ebiten/internal/hooks"
|
||||
"github.com/hajimehoshi/ebiten/internal/input"
|
||||
"github.com/hajimehoshi/ebiten/internal/mainthread"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
)
|
||||
|
||||
@ -58,8 +59,6 @@ type userInterface struct {
|
||||
initWindowDecorated bool
|
||||
initIconImages []image.Image
|
||||
|
||||
funcs chan func()
|
||||
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
@ -102,7 +101,6 @@ func initialize() error {
|
||||
}
|
||||
hideConsoleWindowOnWindows()
|
||||
currentUI.window = window
|
||||
currentUI.funcs = make(chan func())
|
||||
|
||||
currentUI.window.MakeContextCurrent()
|
||||
|
||||
@ -120,23 +118,13 @@ func initialize() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunMainThreadLoop(ch <-chan error) error {
|
||||
// This must be called on the main thread.
|
||||
|
||||
// TODO: Check this is done on the main thread.
|
||||
func Loop(ch <-chan error) error {
|
||||
currentUI.setRunning(true)
|
||||
defer func() {
|
||||
currentUI.setRunning(false)
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case f := <-currentUI.funcs:
|
||||
f()
|
||||
case err := <-ch:
|
||||
// ch returns a value not only when an error occur but also it is closed.
|
||||
return err
|
||||
}
|
||||
if err := mainthread.Loop(ch); err != nil {
|
||||
return err
|
||||
}
|
||||
currentUI.setRunning(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *userInterface) isRunning() bool {
|
||||
@ -217,27 +205,12 @@ func (u *userInterface) setInitIconImages(iconImages []image.Image) {
|
||||
u.m.Unlock()
|
||||
}
|
||||
|
||||
func (u *userInterface) runOnMainThread(f func() error) error {
|
||||
if u.funcs == nil {
|
||||
// already closed
|
||||
return nil
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
var err error
|
||||
u.funcs <- func() {
|
||||
err = f()
|
||||
close(ch)
|
||||
}
|
||||
<-ch
|
||||
return err
|
||||
}
|
||||
|
||||
func ScreenSizeInFullscreen() (int, int) {
|
||||
u := currentUI
|
||||
var v *glfw.VidMode
|
||||
s := 0.0
|
||||
if u.isRunning() {
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
v = u.currentMonitor().GetVideoMode()
|
||||
s = glfwScale()
|
||||
return nil
|
||||
@ -255,7 +228,7 @@ func SetScreenSize(width, height int) bool {
|
||||
panic("ui: Run is not called yet")
|
||||
}
|
||||
r := false
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
r = u.setScreenSize(width, height, u.scale, u.fullscreen(), u.vsync)
|
||||
return nil
|
||||
})
|
||||
@ -268,7 +241,7 @@ func SetScreenScale(scale float64) bool {
|
||||
panic("ui: Run is not called yet")
|
||||
}
|
||||
r := false
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
r = u.setScreenSize(u.width, u.height, scale, u.fullscreen(), u.vsync)
|
||||
return nil
|
||||
})
|
||||
@ -281,7 +254,7 @@ func ScreenScale() float64 {
|
||||
return 0
|
||||
}
|
||||
s := 0.0
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
s = u.scale
|
||||
return nil
|
||||
})
|
||||
@ -302,7 +275,7 @@ func IsFullscreen() bool {
|
||||
return u.isInitFullscreen()
|
||||
}
|
||||
b := false
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
b = u.fullscreen()
|
||||
return nil
|
||||
})
|
||||
@ -315,7 +288,7 @@ func SetFullscreen(fullscreen bool) {
|
||||
u.setInitFullscreen(fullscreen)
|
||||
return
|
||||
}
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
u := currentUI
|
||||
u.setScreenSize(u.width, u.height, u.scale, fullscreen, u.vsync)
|
||||
return nil
|
||||
@ -342,7 +315,7 @@ func SetVsyncEnabled(enabled bool) {
|
||||
u.m.Unlock()
|
||||
return
|
||||
}
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
u := currentUI
|
||||
u.setScreenSize(u.width, u.height, u.scale, u.fullscreen(), enabled)
|
||||
return nil
|
||||
@ -361,7 +334,7 @@ func SetWindowTitle(title string) {
|
||||
if !currentUI.isRunning() {
|
||||
return
|
||||
}
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
currentUI.window.SetTitle(title)
|
||||
return nil
|
||||
})
|
||||
@ -372,7 +345,7 @@ func SetWindowIcon(iconImages []image.Image) {
|
||||
currentUI.setInitIconImages(iconImages)
|
||||
return
|
||||
}
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
currentUI.window.SetIcon(iconImages)
|
||||
return nil
|
||||
})
|
||||
@ -399,7 +372,7 @@ func ScreenPadding() (x0, y0, x1, y1 float64) {
|
||||
sx := 0.0
|
||||
sy := 0.0
|
||||
gs := 0.0
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
sx = float64(u.width) * u.actualScreenScale()
|
||||
sy = float64(u.height) * u.actualScreenScale()
|
||||
gs = glfwScale()
|
||||
@ -424,7 +397,7 @@ func adjustCursorPosition(x, y int) (int, int) {
|
||||
}
|
||||
ox, oy, _, _ := ScreenPadding()
|
||||
s := 0.0
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
s = currentUI.actualScreenScale()
|
||||
return nil
|
||||
})
|
||||
@ -442,7 +415,7 @@ func IsCursorVisible() bool {
|
||||
return u.isInitCursorVisible()
|
||||
}
|
||||
v := false
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
v = currentUI.window.GetInputMode(glfw.CursorMode) == glfw.CursorNormal
|
||||
return nil
|
||||
})
|
||||
@ -455,7 +428,7 @@ func SetCursorVisible(visible bool) {
|
||||
u.setInitCursorVisible(visible)
|
||||
return
|
||||
}
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
c := glfw.CursorNormal
|
||||
if !visible {
|
||||
c = glfw.CursorHidden
|
||||
@ -471,7 +444,7 @@ func IsWindowDecorated() bool {
|
||||
return u.isInitWindowDecorated()
|
||||
}
|
||||
v := false
|
||||
_ = currentUI.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
v = currentUI.window.GetAttrib(glfw.Decorated) == glfw.True
|
||||
return nil
|
||||
})
|
||||
@ -490,7 +463,7 @@ func SetWindowDecorated(decorated bool) {
|
||||
// TODO: Now SetAttrib doesn't exist on GLFW 3.2. Revisit later (#556).
|
||||
// If SetAttrib exists, the implementation would be:
|
||||
//
|
||||
// _ = currentUI.runOnMainThread(func() error {
|
||||
// _ = mainthread.Run(func() error {
|
||||
// v := glfw.False
|
||||
// if decorated {
|
||||
// v = glfw.True
|
||||
@ -506,7 +479,7 @@ func DeviceScaleFactor() float64 {
|
||||
return devicescale.GetAt(u.currentMonitor().GetPos())
|
||||
}
|
||||
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
m := u.currentMonitor()
|
||||
f = devicescale.GetAt(m.GetPos())
|
||||
return nil
|
||||
@ -516,10 +489,7 @@ func DeviceScaleFactor() float64 {
|
||||
|
||||
func Run(width, height int, scale float64, title string, g GraphicsContext, mainloop bool) error {
|
||||
u := currentUI
|
||||
// GLContext must be created before setting the screen size, which requires
|
||||
// swapping buffers.
|
||||
opengl.Init(currentUI.runOnMainThread)
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
// Get the monitor before showing the window.
|
||||
//
|
||||
// On Windows, there are two types of windows:
|
||||
@ -596,7 +566,7 @@ func (u *userInterface) updateGraphicsContext(g GraphicsContext) {
|
||||
actualScale := 0.0
|
||||
sizeChanged := false
|
||||
// TODO: Is it possible to reduce 'runOnMainThread' calls?
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
actualScale = u.actualScreenScale()
|
||||
if u.lastActualScale != actualScale {
|
||||
u.forceSetScreenSize(u.width, u.height, u.scale, u.fullscreen(), u.vsync)
|
||||
@ -618,7 +588,7 @@ func (u *userInterface) updateGraphicsContext(g GraphicsContext) {
|
||||
|
||||
func (u *userInterface) update(g GraphicsContext) error {
|
||||
shouldClose := false
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
shouldClose = u.window.ShouldClose()
|
||||
return nil
|
||||
})
|
||||
@ -626,7 +596,7 @@ func (u *userInterface) update(g GraphicsContext) error {
|
||||
return RegularTermination
|
||||
}
|
||||
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
if u.isInitFullscreen() {
|
||||
u := currentUI
|
||||
u.setScreenSize(u.width, u.height, u.scale, true, u.vsync)
|
||||
@ -638,7 +608,7 @@ func (u *userInterface) update(g GraphicsContext) error {
|
||||
// This call is needed for initialization.
|
||||
u.updateGraphicsContext(g)
|
||||
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
u.pollEvents()
|
||||
defer hooks.ResumeAudio()
|
||||
for !u.isRunnableInBackground() && u.window.GetAttrib(glfw.Focused) == 0 {
|
||||
@ -665,7 +635,7 @@ func (u *userInterface) update(g GraphicsContext) error {
|
||||
|
||||
func (u *userInterface) loop(g GraphicsContext) error {
|
||||
defer func() {
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
glfw.Terminate()
|
||||
return nil
|
||||
})
|
||||
@ -683,7 +653,7 @@ func (u *userInterface) loop(g GraphicsContext) error {
|
||||
// before swapping buffers.
|
||||
opengl.GetContext().BeforeSwapping()
|
||||
|
||||
_ = u.runOnMainThread(func() error {
|
||||
_ = mainthread.Run(func() error {
|
||||
if !vsync {
|
||||
u.swapBuffers()
|
||||
return nil
|
||||
|
@ -357,7 +357,7 @@ func init() {
|
||||
}))
|
||||
}
|
||||
|
||||
func RunMainThreadLoop(ch <-chan error) error {
|
||||
func Loop(ch <-chan error) error {
|
||||
return <-ch
|
||||
}
|
||||
|
||||
@ -366,9 +366,6 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
|
||||
document.Set("title", title)
|
||||
u.setScreenSize(width, height, scale, u.fullscreen)
|
||||
canvas.Call("focus")
|
||||
if err := opengl.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.loop(g)
|
||||
}
|
||||
|
||||
|
@ -166,11 +166,10 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
|
||||
}
|
||||
}
|
||||
|
||||
// RunMainThreadLoop runs the main routine for gomobile-build.
|
||||
func RunMainThreadLoop(ch <-chan error) error {
|
||||
// Loop runs the main routine for gomobile-build.
|
||||
func Loop(ch <-chan error) error {
|
||||
go func() {
|
||||
// As mobile apps never ends, RunMainThreadLoop can't return.
|
||||
// Just panic here.
|
||||
// As mobile apps never ends, Loop can't return. Just panic here.
|
||||
err := <-ch
|
||||
panic(err)
|
||||
}()
|
||||
|
Loading…
Reference in New Issue
Block a user