mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/graphicsdriver/opengl: refactoring: move gl_js to gl/context_js.go
This unifies the OpenGL context interface for all the platforms.
This commit is contained in:
parent
f08983e14d
commit
74d9515345
@ -105,7 +105,7 @@ type context struct {
|
||||
}
|
||||
|
||||
func (c *context) bindTexture(t textureNative) {
|
||||
if c.lastTexture.equal(t) {
|
||||
if c.lastTexture == t {
|
||||
return
|
||||
}
|
||||
c.bindTextureImpl(t)
|
||||
@ -113,7 +113,7 @@ func (c *context) bindTexture(t textureNative) {
|
||||
}
|
||||
|
||||
func (c *context) bindRenderbuffer(r renderbufferNative) {
|
||||
if c.lastRenderbuffer.equal(r) {
|
||||
if c.lastRenderbuffer == r {
|
||||
return
|
||||
}
|
||||
c.bindRenderbufferImpl(r)
|
||||
@ -121,7 +121,7 @@ func (c *context) bindRenderbuffer(r renderbufferNative) {
|
||||
}
|
||||
|
||||
func (c *context) bindFramebuffer(f framebufferNative) {
|
||||
if c.lastFramebuffer.equal(f) {
|
||||
if c.lastFramebuffer == f {
|
||||
return
|
||||
}
|
||||
c.bindFramebufferImpl(f)
|
||||
@ -139,7 +139,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.equal(c.screenFramebuffer) {
|
||||
if f.native == c.screenFramebuffer {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
} else {
|
||||
|
@ -20,62 +20,31 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"syscall/js"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/jsutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type (
|
||||
textureNative js.Value
|
||||
renderbufferNative js.Value
|
||||
framebufferNative js.Value
|
||||
shader js.Value
|
||||
buffer js.Value
|
||||
uniformLocation js.Value
|
||||
|
||||
attribLocation int
|
||||
programID int
|
||||
program struct {
|
||||
value js.Value
|
||||
id programID
|
||||
}
|
||||
textureNative uint32
|
||||
renderbufferNative uint32
|
||||
framebufferNative uint32
|
||||
shader uint32
|
||||
program uint32
|
||||
buffer uint32
|
||||
)
|
||||
|
||||
func (t textureNative) equal(rhs textureNative) bool {
|
||||
return js.Value(t).Equal(js.Value(rhs))
|
||||
}
|
||||
type (
|
||||
uniformLocation int32
|
||||
attribLocation int32
|
||||
)
|
||||
|
||||
func (r renderbufferNative) equal(rhs renderbufferNative) bool {
|
||||
return js.Value(r).Equal(js.Value(rhs))
|
||||
}
|
||||
|
||||
func (f framebufferNative) equal(rhs framebufferNative) bool {
|
||||
return js.Value(f).Equal(js.Value(rhs))
|
||||
}
|
||||
|
||||
func (s shader) equal(rhs shader) bool {
|
||||
return js.Value(s).Equal(js.Value(rhs))
|
||||
}
|
||||
|
||||
func (b buffer) equal(rhs buffer) bool {
|
||||
return js.Value(b).Equal(js.Value(rhs))
|
||||
}
|
||||
|
||||
func (u uniformLocation) equal(rhs uniformLocation) bool {
|
||||
return js.Value(u).Equal(js.Value(rhs))
|
||||
}
|
||||
|
||||
func (p program) equal(rhs program) bool {
|
||||
return p.value.Equal(rhs.value) && p.id == rhs.id
|
||||
}
|
||||
|
||||
var invalidUniform = uniformLocation(js.Null())
|
||||
|
||||
func getProgramID(p program) programID {
|
||||
return p.id
|
||||
}
|
||||
const (
|
||||
invalidFramebuffer = (1 << 32) - 1
|
||||
invalidUniform = -1
|
||||
)
|
||||
|
||||
type webGLVersion int
|
||||
|
||||
@ -97,10 +66,12 @@ func webGL2MightBeAvailable() bool {
|
||||
}
|
||||
|
||||
type contextImpl struct {
|
||||
gl *jsGL
|
||||
canvas js.Value
|
||||
lastProgramID programID
|
||||
webGLVersion webGLVersion
|
||||
ctx gl.Context
|
||||
canvas js.Value
|
||||
webGLVersion webGLVersion
|
||||
|
||||
fnGetExtension js.Value
|
||||
fnIsContextLost js.Value
|
||||
}
|
||||
|
||||
func (c *context) usesWebGL2() bool {
|
||||
@ -110,7 +81,7 @@ func (c *context) usesWebGL2() bool {
|
||||
func (c *context) initGL() error {
|
||||
c.webGLVersion = webGLVersionUnknown
|
||||
|
||||
var gl js.Value
|
||||
var glContext js.Value
|
||||
|
||||
if doc := js.Global().Get("document"); doc.Truthy() {
|
||||
canvas := c.canvas
|
||||
@ -120,36 +91,44 @@ func (c *context) initGL() error {
|
||||
attr.Set("stencil", true)
|
||||
|
||||
if webGL2MightBeAvailable() {
|
||||
gl = canvas.Call("getContext", "webgl2", attr)
|
||||
if gl.Truthy() {
|
||||
glContext = canvas.Call("getContext", "webgl2", attr)
|
||||
if glContext.Truthy() {
|
||||
c.webGLVersion = webGLVersion2
|
||||
}
|
||||
}
|
||||
|
||||
// Even though WebGL2RenderingContext exists, getting a webgl2 context might fail (#1738).
|
||||
if !gl.Truthy() {
|
||||
gl = canvas.Call("getContext", "webgl", attr)
|
||||
if !gl.Truthy() {
|
||||
gl = canvas.Call("getContext", "experimental-webgl", attr)
|
||||
if !glContext.Truthy() {
|
||||
glContext = canvas.Call("getContext", "webgl", attr)
|
||||
if !glContext.Truthy() {
|
||||
glContext = canvas.Call("getContext", "experimental-webgl", attr)
|
||||
}
|
||||
if gl.Truthy() {
|
||||
if glContext.Truthy() {
|
||||
c.webGLVersion = webGLVersion1
|
||||
}
|
||||
}
|
||||
|
||||
if !gl.Truthy() {
|
||||
if !glContext.Truthy() {
|
||||
return fmt.Errorf("opengl: getContext failed")
|
||||
}
|
||||
}
|
||||
|
||||
c.gl = c.newJSGL(gl)
|
||||
ctx, err := gl.NewDefaultContext(glContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.ctx = ctx
|
||||
|
||||
c.fnGetExtension = glContext.Get("getExtension").Call("bind", glContext)
|
||||
c.fnIsContextLost = glContext.Get("isContextLost").Call("bind", glContext)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) reset() error {
|
||||
c.locationCache = newLocationCache()
|
||||
c.lastTexture = textureNative(js.Null())
|
||||
c.lastFramebuffer = framebufferNative(js.Null())
|
||||
c.lastTexture = 0
|
||||
c.lastFramebuffer = invalidFramebuffer
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
c.lastBlend = graphicsdriver.Blend{}
|
||||
@ -158,17 +137,17 @@ func (c *context) reset() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.gl.isContextLost.Invoke().Bool() {
|
||||
if c.fnIsContextLost.Invoke().Bool() {
|
||||
return graphicsdriver.GraphicsNotReady
|
||||
}
|
||||
c.gl.enable.Invoke(gl.BLEND)
|
||||
c.gl.enable.Invoke(gl.SCISSOR_TEST)
|
||||
c.ctx.Enable(gl.BLEND)
|
||||
c.ctx.Enable(gl.SCISSOR_TEST)
|
||||
c.blend(graphicsdriver.BlendSourceOver)
|
||||
f := c.gl.getParameter.Invoke(gl.FRAMEBUFFER_BINDING)
|
||||
f := c.ctx.GetInteger(gl.FRAMEBUFFER_BINDING)
|
||||
c.screenFramebuffer = framebufferNative(f)
|
||||
|
||||
if !c.usesWebGL2() {
|
||||
c.gl.getExtension.Invoke("OES_standard_derivatives")
|
||||
c.fnGetExtension.Invoke("OES_standard_derivatives")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -178,87 +157,85 @@ func (c *context) blend(blend graphicsdriver.Blend) {
|
||||
return
|
||||
}
|
||||
c.lastBlend = blend
|
||||
c.gl.blendFuncSeparate.Invoke(
|
||||
int(convertBlendFactor(blend.BlendFactorSourceRGB)),
|
||||
int(convertBlendFactor(blend.BlendFactorDestinationRGB)),
|
||||
int(convertBlendFactor(blend.BlendFactorSourceAlpha)),
|
||||
int(convertBlendFactor(blend.BlendFactorDestinationAlpha)),
|
||||
c.ctx.BlendFuncSeparate(
|
||||
uint32(convertBlendFactor(blend.BlendFactorSourceRGB)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorDestinationRGB)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorSourceAlpha)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorDestinationAlpha)),
|
||||
)
|
||||
c.gl.blendEquationSeparate.Invoke(
|
||||
int(convertBlendOperation(blend.BlendOperationRGB)),
|
||||
int(convertBlendOperation(blend.BlendOperationAlpha)),
|
||||
c.ctx.BlendEquationSeparate(
|
||||
uint32(convertBlendOperation(blend.BlendOperationRGB)),
|
||||
uint32(convertBlendOperation(blend.BlendOperationAlpha)),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *context) scissor(x, y, width, height int) {
|
||||
c.gl.scissor.Invoke(x, y, width, height)
|
||||
c.ctx.Scissor(int32(x), int32(y), int32(width), int32(height))
|
||||
}
|
||||
|
||||
func (c *context) newTexture(width, height int) (textureNative, error) {
|
||||
t := c.gl.createTexture.Invoke()
|
||||
if !t.Truthy() {
|
||||
return textureNative(js.Null()), errors.New("opengl: createTexture failed")
|
||||
t := c.ctx.CreateTexture()
|
||||
if t <= 0 {
|
||||
return 0, errors.New("opengl: createTexture failed")
|
||||
}
|
||||
c.bindTexture(textureNative(t))
|
||||
|
||||
c.gl.texParameteri.Invoke(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
c.gl.texParameteri.Invoke(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
c.gl.texParameteri.Invoke(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
c.gl.texParameteri.Invoke(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
|
||||
c.ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 4)
|
||||
|
||||
c.gl.pixelStorei.Invoke(gl.UNPACK_ALIGNMENT, 4)
|
||||
// Firefox warns the usage of textures without specifying pixels (#629)
|
||||
//
|
||||
// Error: WebGL warning: drawElements: This operation requires zeroing texture data. This is slow.
|
||||
//
|
||||
// In Ebitengine, textures are filled with pixels laster by the filter that ignores destination, so it is fine
|
||||
// In Ebitengine, textures are filled with pixels later by the filter that ignores destination, so it is fine
|
||||
// to leave textures as uninitialized here. Rather, extra memory allocating for initialization should be
|
||||
// avoided.
|
||||
c.gl.texImage2D.Invoke(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
|
||||
c.ctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, nil)
|
||||
|
||||
return textureNative(t), nil
|
||||
}
|
||||
|
||||
func (c *context) bindFramebufferImpl(f framebufferNative) {
|
||||
c.gl.bindFramebuffer.Invoke(gl.FRAMEBUFFER, js.Value(f))
|
||||
c.ctx.BindFramebuffer(gl.FRAMEBUFFER, uint32(f))
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixels(buf []byte, f *framebuffer, x, y, width, height int) {
|
||||
c.bindFramebuffer(f.native)
|
||||
|
||||
if got, want := len(buf), 4*width*height; got != want {
|
||||
panic(fmt.Sprintf("opengl: len(buf) must be %d but %d", got, want))
|
||||
}
|
||||
|
||||
p := jsutil.TemporaryUint8ArrayFromUint8Slice(len(buf), nil)
|
||||
c.gl.readPixels.Invoke(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, p)
|
||||
js.CopyBytesToGo(buf, p)
|
||||
c.bindFramebuffer(f.native)
|
||||
c.ctx.ReadPixels(buf, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {
|
||||
c.bindFramebuffer(f.native)
|
||||
c.gl.bindBuffer.Invoke(gl.PIXEL_PACK_BUFFER, js.Value(buffer))
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, uint32(buffer))
|
||||
// void gl.readPixels(x, y, width, height, format, type, GLintptr offset);
|
||||
c.gl.readPixels.Invoke(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, 0)
|
||||
c.gl.bindBuffer.Invoke(gl.PIXEL_PACK_BUFFER, nil)
|
||||
c.ctx.ReadPixels(nil, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, 0)
|
||||
}
|
||||
|
||||
func (c *context) activeTexture(idx int) {
|
||||
c.gl.activeTexture.Invoke(gl.TEXTURE0 + idx)
|
||||
c.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
|
||||
}
|
||||
|
||||
func (c *context) bindTextureImpl(t textureNative) {
|
||||
c.gl.bindTexture.Invoke(gl.TEXTURE_2D, js.Value(t))
|
||||
c.ctx.BindTexture(gl.TEXTURE_2D, uint32(t))
|
||||
}
|
||||
|
||||
func (c *context) deleteTexture(t textureNative) {
|
||||
if !c.gl.isTexture.Invoke(js.Value(t)).Bool() {
|
||||
if !c.ctx.IsTexture(uint32(t)) {
|
||||
return
|
||||
}
|
||||
if c.lastTexture.equal(t) {
|
||||
c.lastTexture = textureNative(js.Null())
|
||||
if c.lastTexture == t {
|
||||
c.lastTexture = 0
|
||||
}
|
||||
c.gl.deleteTexture.Invoke(js.Value(t))
|
||||
c.ctx.DeleteTexture(uint32(t))
|
||||
}
|
||||
|
||||
func (c *context) isTexture(t textureNative) bool {
|
||||
@ -267,40 +244,45 @@ func (c *context) isTexture(t textureNative) bool {
|
||||
}
|
||||
|
||||
func (c *context) newRenderbuffer(width, height int) (renderbufferNative, error) {
|
||||
r := c.gl.createRenderbuffer.Invoke()
|
||||
if !r.Truthy() {
|
||||
return renderbufferNative(js.Null()), errors.New("opengl: createRenderbuffer failed")
|
||||
r := c.ctx.CreateRenderbuffer()
|
||||
if r <= 0 {
|
||||
return 0, errors.New("opengl: createRenderbuffer failed")
|
||||
}
|
||||
|
||||
c.bindRenderbuffer(renderbufferNative(r))
|
||||
renderbuffer := renderbufferNative(r)
|
||||
c.bindRenderbuffer(renderbuffer)
|
||||
|
||||
// TODO: Is STENCIL_INDEX8 portable?
|
||||
// https://stackoverflow.com/questions/11084961/binding-a-stencil-render-buffer-to-a-frame-buffer-in-opengl
|
||||
c.gl.renderbufferStorage.Invoke(gl.RENDERBUFFER, gl.STENCIL_INDEX8, width, height)
|
||||
c.ctx.RenderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, int32(width), int32(height))
|
||||
|
||||
return renderbufferNative(r), nil
|
||||
return renderbuffer, nil
|
||||
}
|
||||
|
||||
func (c *context) bindRenderbufferImpl(r renderbufferNative) {
|
||||
c.gl.bindRenderbuffer.Invoke(gl.RENDERBUFFER, js.Value(r))
|
||||
c.ctx.BindRenderbuffer(gl.RENDERBUFFER, uint32(r))
|
||||
}
|
||||
|
||||
func (c *context) deleteRenderbuffer(r renderbufferNative) {
|
||||
if !c.gl.isRenderbuffer.Invoke(js.Value(r)).Bool() {
|
||||
if !c.ctx.IsRenderbuffer(uint32(r)) {
|
||||
return
|
||||
}
|
||||
if c.lastRenderbuffer.equal(r) {
|
||||
c.lastRenderbuffer = renderbufferNative(js.Null())
|
||||
if c.lastRenderbuffer == r {
|
||||
c.lastRenderbuffer = 0
|
||||
}
|
||||
c.gl.deleteRenderbuffer.Invoke(js.Value(r))
|
||||
c.ctx.DeleteRenderbuffer(uint32(r))
|
||||
}
|
||||
|
||||
func (c *context) newFramebuffer(t textureNative) (framebufferNative, error) {
|
||||
f := c.gl.createFramebuffer.Invoke()
|
||||
f := c.ctx.CreateFramebuffer()
|
||||
if f <= 0 {
|
||||
return 0, fmt.Errorf("opengl: creating framebuffer failed: the returned value is not positive but %d", f)
|
||||
}
|
||||
c.bindFramebuffer(framebufferNative(f))
|
||||
|
||||
c.gl.framebufferTexture2D.Invoke(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, js.Value(t), 0)
|
||||
if s := c.gl.checkFramebufferStatus.Invoke(gl.FRAMEBUFFER); s.Int() != gl.FRAMEBUFFER_COMPLETE {
|
||||
return framebufferNative(js.Null()), errors.New(fmt.Sprintf("opengl: creating framebuffer failed: %d", s.Int()))
|
||||
c.ctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(t), 0)
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
return 0, errors.New(fmt.Sprintf("opengl: creating framebuffer failed: %d", s))
|
||||
}
|
||||
|
||||
return framebufferNative(f), nil
|
||||
@ -309,30 +291,30 @@ func (c *context) newFramebuffer(t textureNative) (framebufferNative, error) {
|
||||
func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) error {
|
||||
c.bindFramebuffer(f)
|
||||
|
||||
c.gl.framebufferRenderbuffer.Invoke(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, js.Value(r))
|
||||
if s := c.gl.checkFramebufferStatus.Invoke(gl.FRAMEBUFFER); s.Int() != gl.FRAMEBUFFER_COMPLETE {
|
||||
return errors.New(fmt.Sprintf("opengl: framebufferRenderbuffer failed: %d", s.Int()))
|
||||
c.ctx.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, uint32(r))
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
return errors.New(fmt.Sprintf("opengl: framebufferRenderbuffer failed: %d", s))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) setViewportImpl(width, height int) {
|
||||
c.gl.viewport.Invoke(0, 0, width, height)
|
||||
c.ctx.Viewport(0, 0, int32(width), int32(height))
|
||||
}
|
||||
|
||||
func (c *context) deleteFramebuffer(f framebufferNative) {
|
||||
if !c.gl.isFramebuffer.Invoke(js.Value(f)).Bool() {
|
||||
if !c.ctx.IsFramebuffer(uint32(f)) {
|
||||
return
|
||||
}
|
||||
// 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.equal(f) {
|
||||
c.lastFramebuffer = framebufferNative(js.Null())
|
||||
if c.lastFramebuffer == f {
|
||||
c.lastFramebuffer = invalidFramebuffer
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
}
|
||||
c.gl.deleteFramebuffer.Invoke(js.Value(f))
|
||||
c.ctx.DeleteFramebuffer(uint32(f))
|
||||
}
|
||||
|
||||
func (c *context) newVertexShader(source string) (shader, error) {
|
||||
@ -343,83 +325,78 @@ func (c *context) newFragmentShader(source string) (shader, error) {
|
||||
return c.newShader(gl.FRAGMENT_SHADER, source)
|
||||
}
|
||||
|
||||
func (c *context) newShader(shaderType int, source string) (shader, error) {
|
||||
s := c.gl.createShader.Invoke(int(shaderType))
|
||||
if !s.Truthy() {
|
||||
return shader(js.Null()), fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
|
||||
func (c *context) newShader(shaderType uint32, source string) (shader, error) {
|
||||
s := c.ctx.CreateShader(shaderType)
|
||||
if s == 0 {
|
||||
return 0, fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
|
||||
}
|
||||
|
||||
c.gl.shaderSource.Invoke(js.Value(s), source)
|
||||
c.gl.compileShader.Invoke(js.Value(s))
|
||||
c.ctx.ShaderSource(s, source)
|
||||
c.ctx.CompileShader(s)
|
||||
|
||||
if !c.gl.getShaderParameter.Invoke(js.Value(s), gl.COMPILE_STATUS).Bool() {
|
||||
log := c.gl.getShaderInfoLog.Invoke(js.Value(s))
|
||||
return shader(js.Null()), fmt.Errorf("opengl: shader compile failed: %s", log)
|
||||
if c.ctx.GetShaderi(s, gl.COMPILE_STATUS) == gl.FALSE {
|
||||
log := c.ctx.GetShaderInfoLog(s)
|
||||
return 0, fmt.Errorf("opengl: shader compile failed: %s", log)
|
||||
}
|
||||
return shader(s), nil
|
||||
}
|
||||
|
||||
func (c *context) deleteShader(s shader) {
|
||||
c.gl.deleteShader.Invoke(js.Value(s))
|
||||
c.ctx.DeleteShader(uint32(s))
|
||||
}
|
||||
|
||||
func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
|
||||
v := c.gl.createProgram.Invoke()
|
||||
if !v.Truthy() {
|
||||
return program{}, errors.New("opengl: glCreateProgram failed")
|
||||
p := c.ctx.CreateProgram()
|
||||
if p == 0 {
|
||||
return 0, errors.New("opengl: glCreateProgram failed")
|
||||
}
|
||||
|
||||
for _, shader := range shaders {
|
||||
c.gl.attachShader.Invoke(v, js.Value(shader))
|
||||
c.ctx.AttachShader(p, uint32(shader))
|
||||
}
|
||||
|
||||
for i, name := range attributes {
|
||||
c.gl.bindAttribLocation.Invoke(v, i, name)
|
||||
c.ctx.BindAttribLocation(p, uint32(i), name)
|
||||
}
|
||||
|
||||
c.gl.linkProgram.Invoke(v)
|
||||
if !c.gl.getProgramParameter.Invoke(v, gl.LINK_STATUS).Bool() {
|
||||
info := c.gl.getProgramInfoLog.Invoke(v).String()
|
||||
return program{}, fmt.Errorf("opengl: program error: %s", info)
|
||||
c.ctx.LinkProgram(p)
|
||||
if c.ctx.GetProgrami(p, gl.LINK_STATUS) == gl.FALSE {
|
||||
info := c.ctx.GetProgramInfoLog(p)
|
||||
return 0, fmt.Errorf("opengl: program error: %s", info)
|
||||
}
|
||||
|
||||
id := c.lastProgramID
|
||||
c.lastProgramID++
|
||||
return program{
|
||||
value: v,
|
||||
id: id,
|
||||
}, nil
|
||||
return program(p), nil
|
||||
}
|
||||
|
||||
func (c *context) useProgram(p program) {
|
||||
c.gl.useProgram.Invoke(p.value)
|
||||
c.ctx.UseProgram(uint32(p))
|
||||
}
|
||||
|
||||
func (c *context) deleteProgram(p program) {
|
||||
c.locationCache.deleteProgram(p)
|
||||
|
||||
if !c.gl.isProgram.Invoke(p.value).Bool() {
|
||||
if !c.ctx.IsProgram(uint32(p)) {
|
||||
return
|
||||
}
|
||||
c.gl.deleteProgram.Invoke(p.value)
|
||||
c.ctx.DeleteProgram(uint32(p))
|
||||
}
|
||||
|
||||
func (c *context) getUniformLocationImpl(p program, location string) uniformLocation {
|
||||
return uniformLocation(c.gl.getUniformLocation.Invoke(p.value, location))
|
||||
return uniformLocation(c.ctx.GetUniformLocation(uint32(p), location))
|
||||
}
|
||||
|
||||
func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l.equal(invalidUniform) {
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
}
|
||||
c.gl.uniform1i.Invoke(js.Value(l), v)
|
||||
c.ctx.Uniform1i(int32(l), int32(v))
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.Type) bool {
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l.equal(invalidUniform) {
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -430,178 +407,115 @@ func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.
|
||||
|
||||
switch base {
|
||||
case shaderir.Float:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniform1fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniform1fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.Uniform1fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Int:
|
||||
arr := jsutil.TemporaryInt32Array(len(v), uint32sToInt32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniform1iv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniform1iv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.Uniform1iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.Vec2:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniform2fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniform2fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.Uniform2fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec3:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniform3fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniform3fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.Uniform3fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec4:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniform4fv.Invoke(js.Value(l), arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniform4fv.Invoke(js.Value(l), arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.Uniform4fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat2:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniformMatrix2fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniformMatrix2fv.Invoke(js.Value(l), false, arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.UniformMatrix2fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat3:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniformMatrix3fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniformMatrix3fv.Invoke(js.Value(l), false, arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.UniformMatrix3fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat4:
|
||||
arr := jsutil.TemporaryFloat32Array(len(v), uint32sToFloat32s(v))
|
||||
if c.usesWebGL2() {
|
||||
c.gl.uniformMatrix4fv.Invoke(js.Value(l), false, arr, 0, len(v))
|
||||
} else {
|
||||
c.gl.uniformMatrix4fv.Invoke(js.Value(l), false, arr.Call("subarray", 0, len(v)))
|
||||
}
|
||||
c.ctx.UniformMatrix4fv(int32(l), uint32sToFloat32s(v))
|
||||
default:
|
||||
panic(fmt.Sprintf("opengl: unexpected type: %s", typ.String()))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) vertexAttribPointer(index int, size int, stride int, offset int) {
|
||||
c.gl.vertexAttribPointer.Invoke(index, size, gl.FLOAT, false, stride, offset)
|
||||
c.ctx.VertexAttribPointer(uint32(index), int32(size), gl.FLOAT, false, int32(stride), offset)
|
||||
}
|
||||
|
||||
func (c *context) enableVertexAttribArray(index int) {
|
||||
c.gl.enableVertexAttribArray.Invoke(index)
|
||||
c.ctx.EnableVertexAttribArray(uint32(index))
|
||||
}
|
||||
|
||||
func (c *context) disableVertexAttribArray(index int) {
|
||||
c.gl.disableVertexAttribArray.Invoke(index)
|
||||
c.ctx.DisableVertexAttribArray(uint32(index))
|
||||
}
|
||||
|
||||
func (c *context) newArrayBuffer(size int) buffer {
|
||||
b := c.gl.createBuffer.Invoke()
|
||||
c.gl.bindBuffer.Invoke(gl.ARRAY_BUFFER, js.Value(b))
|
||||
c.gl.bufferData.Invoke(gl.ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
b := c.ctx.CreateBuffer()
|
||||
c.ctx.BindBuffer(gl.ARRAY_BUFFER, b)
|
||||
c.ctx.BufferInit(gl.ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
return buffer(b)
|
||||
}
|
||||
|
||||
func (c *context) newElementArrayBuffer(size int) buffer {
|
||||
b := c.gl.createBuffer.Invoke()
|
||||
c.gl.bindBuffer.Invoke(gl.ELEMENT_ARRAY_BUFFER, js.Value(b))
|
||||
c.gl.bufferData.Invoke(gl.ELEMENT_ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
b := c.ctx.CreateBuffer()
|
||||
c.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, b)
|
||||
c.ctx.BufferInit(gl.ELEMENT_ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
return buffer(b)
|
||||
}
|
||||
|
||||
func (c *context) bindArrayBuffer(b buffer) {
|
||||
c.gl.bindBuffer.Invoke(gl.ARRAY_BUFFER, js.Value(b))
|
||||
c.ctx.BindBuffer(gl.ARRAY_BUFFER, uint32(b))
|
||||
}
|
||||
|
||||
func (c *context) bindElementArrayBuffer(b buffer) {
|
||||
c.gl.bindBuffer.Invoke(gl.ELEMENT_ARRAY_BUFFER, js.Value(b))
|
||||
c.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, uint32(b))
|
||||
}
|
||||
|
||||
func (c *context) arrayBufferSubData(data []float32) {
|
||||
l := len(data) * 4
|
||||
arr := jsutil.TemporaryUint8ArrayFromFloat32Slice(l, data)
|
||||
if c.usesWebGL2() {
|
||||
c.gl.bufferSubData.Invoke(gl.ARRAY_BUFFER, 0, arr, 0, l)
|
||||
} else {
|
||||
c.gl.bufferSubData.Invoke(gl.ARRAY_BUFFER, 0, arr.Call("subarray", 0, l))
|
||||
}
|
||||
s := unsafe.Slice((*byte)(unsafe.Pointer(&data[0])), len(data)*4)
|
||||
c.ctx.BufferSubData(gl.ARRAY_BUFFER, 0, s)
|
||||
}
|
||||
|
||||
func (c *context) elementArrayBufferSubData(data []uint16) {
|
||||
l := len(data) * 2
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint16Slice(l, data)
|
||||
if c.usesWebGL2() {
|
||||
c.gl.bufferSubData.Invoke(gl.ELEMENT_ARRAY_BUFFER, 0, arr, 0, l)
|
||||
} else {
|
||||
c.gl.bufferSubData.Invoke(gl.ELEMENT_ARRAY_BUFFER, 0, arr.Call("subarray", 0, l))
|
||||
}
|
||||
s := unsafe.Slice((*byte)(unsafe.Pointer(&data[0])), len(data)*2)
|
||||
c.ctx.BufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, s)
|
||||
}
|
||||
|
||||
func (c *context) deleteBuffer(b buffer) {
|
||||
c.gl.deleteBuffer.Invoke(js.Value(b))
|
||||
c.ctx.DeleteBuffer(uint32(b))
|
||||
}
|
||||
|
||||
func (c *context) drawElements(len int, offsetInBytes int) {
|
||||
c.gl.drawElements.Invoke(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, offsetInBytes)
|
||||
c.ctx.DrawElements(gl.TRIANGLES, int32(len), gl.UNSIGNED_SHORT, offsetInBytes)
|
||||
}
|
||||
|
||||
func (c *context) maxTextureSizeImpl() int {
|
||||
return c.gl.getParameter.Invoke(gl.MAX_TEXTURE_SIZE).Int()
|
||||
return c.ctx.GetInteger(gl.MAX_TEXTURE_SIZE)
|
||||
}
|
||||
|
||||
func (c *context) flush() {
|
||||
c.gl.flush.Invoke()
|
||||
c.ctx.Flush()
|
||||
}
|
||||
|
||||
func (c *context) texSubImage2D(t textureNative, args []*graphicsdriver.WritePixelsArgs) {
|
||||
c.bindTexture(t)
|
||||
for _, a := range args {
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(len(a.Pixels), a.Pixels)
|
||||
if c.usesWebGL2() {
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView pixels, srcOffset);
|
||||
c.gl.texSubImage2D.Invoke(gl.TEXTURE_2D, 0, a.X, a.Y, a.Width, a.Height, gl.RGBA, gl.UNSIGNED_BYTE, arr, 0)
|
||||
} else {
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView? pixels);
|
||||
c.gl.texSubImage2D.Invoke(gl.TEXTURE_2D, 0, a.X, a.Y, a.Width, a.Height, gl.RGBA, gl.UNSIGNED_BYTE, arr)
|
||||
}
|
||||
c.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) enableStencilTest() {
|
||||
c.gl.enable.Invoke(gl.STENCIL_TEST)
|
||||
c.ctx.Enable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
func (c *context) disableStencilTest() {
|
||||
c.gl.disable.Invoke(gl.STENCIL_TEST)
|
||||
c.ctx.Disable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
func (c *context) beginStencilWithEvenOddRule() {
|
||||
c.gl.clear.Invoke(gl.STENCIL_BUFFER_BIT)
|
||||
c.gl.stencilFunc.Invoke(gl.ALWAYS, 0x00, 0xff)
|
||||
c.gl.stencilOp.Invoke(gl.KEEP, gl.KEEP, gl.INVERT)
|
||||
c.gl.colorMask.Invoke(false, false, false, false)
|
||||
c.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||
c.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||
c.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
|
||||
c.ctx.ColorMask(false, false, false, false)
|
||||
}
|
||||
|
||||
func (c *context) endStencilWithEvenOddRule() {
|
||||
c.gl.stencilFunc.Invoke(gl.NOTEQUAL, 0x00, 0xff)
|
||||
c.gl.stencilOp.Invoke(gl.KEEP, gl.KEEP, gl.KEEP)
|
||||
c.gl.colorMask.Invoke(true, true, true, true)
|
||||
c.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
||||
c.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
|
||||
c.ctx.ColorMask(true, true, true, true)
|
||||
}
|
||||
|
||||
func (c *context) isES() bool {
|
||||
// WebGL is compatible with GLES.
|
||||
return true
|
||||
return c.ctx.IsES()
|
||||
}
|
||||
|
@ -35,50 +35,16 @@ type (
|
||||
buffer uint32
|
||||
)
|
||||
|
||||
func (t textureNative) equal(rhs textureNative) bool {
|
||||
return t == rhs
|
||||
}
|
||||
|
||||
func (r renderbufferNative) equal(rhs renderbufferNative) bool {
|
||||
return r == 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
|
||||
}
|
||||
|
||||
type (
|
||||
uniformLocation int32
|
||||
attribLocation int32
|
||||
)
|
||||
|
||||
func (u uniformLocation) equal(rhs uniformLocation) bool {
|
||||
return u == rhs
|
||||
}
|
||||
|
||||
type programID uint32
|
||||
|
||||
const (
|
||||
invalidFramebuffer = (1 << 32) - 1
|
||||
invalidUniform = -1
|
||||
)
|
||||
|
||||
func getProgramID(p program) programID {
|
||||
return programID(p)
|
||||
}
|
||||
|
||||
type contextImpl struct {
|
||||
ctx gl.Context
|
||||
init bool
|
||||
@ -150,10 +116,12 @@ func (c *context) bindFramebufferImpl(f framebufferNative) {
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixels(buf []byte, f *framebuffer, x, y, width, height int) {
|
||||
if got, want := len(buf), 4*width*height; got != want {
|
||||
panic(fmt.Sprintf("opengl: len(buf) must be %d but %d", got, want))
|
||||
}
|
||||
|
||||
c.ctx.Flush()
|
||||
|
||||
c.bindFramebuffer(f.native)
|
||||
|
||||
c.ctx.ReadPixels(buf, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
}
|
||||
|
||||
@ -213,7 +181,7 @@ func (c *context) deleteRenderbuffer(r renderbufferNative) {
|
||||
if !c.ctx.IsRenderbuffer(uint32(r)) {
|
||||
return
|
||||
}
|
||||
if c.lastRenderbuffer.equal(r) {
|
||||
if c.lastRenderbuffer == r {
|
||||
c.lastRenderbuffer = 0
|
||||
}
|
||||
c.ctx.DeleteRenderbuffer(uint32(r))
|
||||
@ -332,8 +300,7 @@ func (c *context) deleteProgram(p program) {
|
||||
}
|
||||
|
||||
func (c *context) getUniformLocationImpl(p program, location string) uniformLocation {
|
||||
u := uniformLocation(c.ctx.GetUniformLocation(uint32(p), location))
|
||||
return u
|
||||
return uniformLocation(c.ctx.GetUniformLocation(uint32(p), location))
|
||||
}
|
||||
|
||||
func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
|
@ -45,7 +45,7 @@ func newScreenFramebuffer(context *context, width, height int) *framebuffer {
|
||||
}
|
||||
|
||||
func (f *framebuffer) delete(context *context) {
|
||||
if !f.native.equal(context.getScreenFramebuffer()) {
|
||||
if f.native != context.getScreenFramebuffer() {
|
||||
context.deleteFramebuffer(f.native)
|
||||
}
|
||||
}
|
||||
|
645
internal/graphicsdriver/opengl/gl/default_js.go
Normal file
645
internal/graphicsdriver/opengl/gl/default_js.go
Normal file
@ -0,0 +1,645 @@
|
||||
// Copyright 2022 The Ebitengine 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 gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/jsutil"
|
||||
)
|
||||
|
||||
type defaultContext struct {
|
||||
fnActiveTexture js.Value
|
||||
fnAttachShader js.Value
|
||||
fnBindAttribLocation js.Value
|
||||
fnBindBuffer js.Value
|
||||
fnBindFramebuffer js.Value
|
||||
fnBindRenderbuffer js.Value
|
||||
fnBindTexture js.Value
|
||||
fnBlendEquationSeparate js.Value
|
||||
fnBlendFuncSeparate js.Value
|
||||
fnBufferData js.Value
|
||||
fnBufferSubData js.Value
|
||||
fnCheckFramebufferStatus js.Value
|
||||
fnClear js.Value
|
||||
fnColorMask js.Value
|
||||
fnCompileShader js.Value
|
||||
fnCreateBuffer js.Value
|
||||
fnCreateFramebuffer js.Value
|
||||
fnCreateProgram js.Value
|
||||
fnCreateRenderbuffer js.Value
|
||||
fnCreateShader js.Value
|
||||
fnCreateTexture js.Value
|
||||
fnDeleteBuffer js.Value
|
||||
fnDeleteFramebuffer js.Value
|
||||
fnDeleteProgram js.Value
|
||||
fnDeleteRenderbuffer js.Value
|
||||
fnDeleteShader js.Value
|
||||
fnDeleteTexture js.Value
|
||||
fnDisable js.Value
|
||||
fnDisableVertexAttribArray js.Value
|
||||
fnDrawElements js.Value
|
||||
fnEnable js.Value
|
||||
fnEnableVertexAttribArray js.Value
|
||||
fnFramebufferRenderbuffer js.Value
|
||||
fnFramebufferTexture2D js.Value
|
||||
fnFlush js.Value
|
||||
fnGetError js.Value
|
||||
fnGetParameter js.Value
|
||||
fnGetProgramInfoLog js.Value
|
||||
fnGetProgramParameter js.Value
|
||||
fnGetShaderInfoLog js.Value
|
||||
fnGetShaderParameter js.Value
|
||||
fnGetUniformLocation js.Value
|
||||
fnIsFramebuffer js.Value
|
||||
fnIsProgram js.Value
|
||||
fnIsRenderbuffer js.Value
|
||||
fnIsTexture js.Value
|
||||
fnLinkProgram js.Value
|
||||
fnPixelStorei js.Value
|
||||
fnReadPixels js.Value
|
||||
fnRenderbufferStorage js.Value
|
||||
fnScissor js.Value
|
||||
fnShaderSource js.Value
|
||||
fnStencilFunc js.Value
|
||||
fnStencilMask js.Value
|
||||
fnStencilOp js.Value
|
||||
fnTexImage2D js.Value
|
||||
fnTexSubImage2D js.Value
|
||||
fnTexParameteri js.Value
|
||||
fnUniform1fv js.Value
|
||||
fnUniform1i js.Value
|
||||
fnUniform1iv js.Value
|
||||
fnUniform2fv js.Value
|
||||
fnUniform3fv js.Value
|
||||
fnUniform4fv js.Value
|
||||
fnUniformMatrix2fv js.Value
|
||||
fnUniformMatrix3fv js.Value
|
||||
fnUniformMatrix4fv js.Value
|
||||
fnUseProgram js.Value
|
||||
fnVertexAttribPointer js.Value
|
||||
fnViewport js.Value
|
||||
|
||||
webGL2 bool
|
||||
|
||||
buffers values
|
||||
framebuffers values
|
||||
programs values
|
||||
renderbuffers values
|
||||
shaders values
|
||||
textures values
|
||||
uniformLocations map[uint32]*values
|
||||
}
|
||||
|
||||
type values struct {
|
||||
idToValue map[uint32]js.Value
|
||||
lastID uint32
|
||||
}
|
||||
|
||||
func (v *values) create(value js.Value) uint32 {
|
||||
v.lastID++
|
||||
id := v.lastID
|
||||
if v.idToValue == nil {
|
||||
v.idToValue = map[uint32]js.Value{}
|
||||
}
|
||||
v.idToValue[id] = value
|
||||
return id
|
||||
}
|
||||
|
||||
func (v *values) get(id uint32) js.Value {
|
||||
return v.idToValue[id]
|
||||
}
|
||||
|
||||
func (v *values) getID(value js.Value) (uint32, bool) {
|
||||
for id, v := range v.idToValue {
|
||||
if v.Equal(value) {
|
||||
return id, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (v *values) getOrCreate(value js.Value) uint32 {
|
||||
id, ok := v.getID(value)
|
||||
if ok {
|
||||
return id
|
||||
}
|
||||
return v.create(value)
|
||||
}
|
||||
|
||||
func (v *values) delete(id uint32) {
|
||||
delete(v.idToValue, id)
|
||||
}
|
||||
|
||||
func NewDefaultContext(v js.Value) (Context, error) {
|
||||
// Passing a Go string to the JS world is expensive. This causes conversion to UTF-16 (#1438).
|
||||
// In order to reduce the cost when calling functions, create the function objects by bind and use them.
|
||||
g := &defaultContext{
|
||||
fnActiveTexture: v.Get("activeTexture").Call("bind", v),
|
||||
fnAttachShader: v.Get("attachShader").Call("bind", v),
|
||||
fnBindAttribLocation: v.Get("bindAttribLocation").Call("bind", v),
|
||||
fnBindBuffer: v.Get("bindBuffer").Call("bind", v),
|
||||
fnBindFramebuffer: v.Get("bindFramebuffer").Call("bind", v),
|
||||
fnBindRenderbuffer: v.Get("bindRenderbuffer").Call("bind", v),
|
||||
fnBindTexture: v.Get("bindTexture").Call("bind", v),
|
||||
fnBlendEquationSeparate: v.Get("blendEquationSeparate").Call("bind", v),
|
||||
fnBlendFuncSeparate: v.Get("blendFuncSeparate").Call("bind", v),
|
||||
fnBufferData: v.Get("bufferData").Call("bind", v),
|
||||
fnBufferSubData: v.Get("bufferSubData").Call("bind", v),
|
||||
fnCheckFramebufferStatus: v.Get("checkFramebufferStatus").Call("bind", v),
|
||||
fnClear: v.Get("clear").Call("bind", v),
|
||||
fnColorMask: v.Get("colorMask").Call("bind", v),
|
||||
fnCompileShader: v.Get("compileShader").Call("bind", v),
|
||||
fnCreateBuffer: v.Get("createBuffer").Call("bind", v),
|
||||
fnCreateFramebuffer: v.Get("createFramebuffer").Call("bind", v),
|
||||
fnCreateProgram: v.Get("createProgram").Call("bind", v),
|
||||
fnCreateRenderbuffer: v.Get("createRenderbuffer").Call("bind", v),
|
||||
fnCreateShader: v.Get("createShader").Call("bind", v),
|
||||
fnCreateTexture: v.Get("createTexture").Call("bind", v),
|
||||
fnDeleteBuffer: v.Get("deleteBuffer").Call("bind", v),
|
||||
fnDeleteFramebuffer: v.Get("deleteFramebuffer").Call("bind", v),
|
||||
fnDeleteProgram: v.Get("deleteProgram").Call("bind", v),
|
||||
fnDeleteRenderbuffer: v.Get("deleteRenderbuffer").Call("bind", v),
|
||||
fnDeleteShader: v.Get("deleteShader").Call("bind", v),
|
||||
fnDeleteTexture: v.Get("deleteTexture").Call("bind", v),
|
||||
fnDisable: v.Get("disable").Call("bind", v),
|
||||
fnDisableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
|
||||
fnDrawElements: v.Get("drawElements").Call("bind", v),
|
||||
fnEnable: v.Get("enable").Call("bind", v),
|
||||
fnEnableVertexAttribArray: v.Get("enableVertexAttribArray").Call("bind", v),
|
||||
fnFramebufferRenderbuffer: v.Get("framebufferRenderbuffer").Call("bind", v),
|
||||
fnFramebufferTexture2D: v.Get("framebufferTexture2D").Call("bind", v),
|
||||
fnFlush: v.Get("flush").Call("bind", v),
|
||||
fnGetError: v.Get("getError").Call("bind", v),
|
||||
fnGetParameter: v.Get("getParameter").Call("bind", v),
|
||||
fnGetProgramInfoLog: v.Get("getProgramInfoLog").Call("bind", v),
|
||||
fnGetProgramParameter: v.Get("getProgramParameter").Call("bind", v),
|
||||
fnGetShaderInfoLog: v.Get("getShaderInfoLog").Call("bind", v),
|
||||
fnGetShaderParameter: v.Get("getShaderParameter").Call("bind", v),
|
||||
fnGetUniformLocation: v.Get("getUniformLocation").Call("bind", v),
|
||||
fnIsFramebuffer: v.Get("isFramebuffer").Call("bind", v),
|
||||
fnIsProgram: v.Get("isProgram").Call("bind", v),
|
||||
fnIsRenderbuffer: v.Get("isRenderbuffer").Call("bind", v),
|
||||
fnIsTexture: v.Get("isTexture").Call("bind", v),
|
||||
fnLinkProgram: v.Get("linkProgram").Call("bind", v),
|
||||
fnPixelStorei: v.Get("pixelStorei").Call("bind", v),
|
||||
fnReadPixels: v.Get("readPixels").Call("bind", v),
|
||||
fnRenderbufferStorage: v.Get("renderbufferStorage").Call("bind", v),
|
||||
fnScissor: v.Get("scissor").Call("bind", v),
|
||||
fnShaderSource: v.Get("shaderSource").Call("bind", v),
|
||||
fnStencilFunc: v.Get("stencilFunc").Call("bind", v),
|
||||
fnStencilMask: v.Get("stencilMask").Call("bind", v),
|
||||
fnStencilOp: v.Get("stencilOp").Call("bind", v),
|
||||
fnTexImage2D: v.Get("texImage2D").Call("bind", v),
|
||||
fnTexSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
||||
fnTexParameteri: v.Get("texParameteri").Call("bind", v),
|
||||
fnUniform1fv: v.Get("uniform1fv").Call("bind", v),
|
||||
fnUniform1i: v.Get("uniform1i").Call("bind", v),
|
||||
fnUniform1iv: v.Get("uniform1iv").Call("bind", v),
|
||||
fnUniform2fv: v.Get("uniform2fv").Call("bind", v),
|
||||
fnUniform3fv: v.Get("uniform3fv").Call("bind", v),
|
||||
fnUniform4fv: v.Get("uniform4fv").Call("bind", v),
|
||||
fnUniformMatrix2fv: v.Get("uniformMatrix2fv").Call("bind", v),
|
||||
fnUniformMatrix3fv: v.Get("uniformMatrix3fv").Call("bind", v),
|
||||
fnUniformMatrix4fv: v.Get("uniformMatrix4fv").Call("bind", v),
|
||||
fnUseProgram: v.Get("useProgram").Call("bind", v),
|
||||
fnVertexAttribPointer: v.Get("vertexAttribPointer").Call("bind", v),
|
||||
fnViewport: v.Get("viewport").Call("bind", v),
|
||||
}
|
||||
|
||||
if webGL2 := js.Global().Get("WebGL2RenderingContext"); webGL2.Truthy() {
|
||||
g.webGL2 = v.InstanceOf(webGL2)
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) getUniformLocation(location int32) js.Value {
|
||||
program := uint32(location) >> 5
|
||||
return c.uniformLocations[program].get(uint32(location) & ((1 << 5) - 1))
|
||||
}
|
||||
|
||||
func (c *defaultContext) LoadFunctions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsES() bool {
|
||||
// WebGL is compatible with GLES.
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *defaultContext) ActiveTexture(texture uint32) {
|
||||
c.fnActiveTexture.Invoke(texture)
|
||||
}
|
||||
|
||||
func (c *defaultContext) AttachShader(program uint32, shader uint32) {
|
||||
c.fnAttachShader.Invoke(c.programs.get(program), c.shaders.get(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
c.fnBindAttribLocation.Invoke(c.programs.get(program), index, name)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindBuffer(target uint32, buffer uint32) {
|
||||
c.fnBindBuffer.Invoke(target, c.buffers.get(buffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindFramebuffer(target uint32, framebuffer uint32) {
|
||||
c.fnBindFramebuffer.Invoke(target, c.framebuffers.get(framebuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindRenderbuffer(target uint32, renderbuffer uint32) {
|
||||
c.fnBindRenderbuffer.Invoke(target, c.renderbuffers.get(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindTexture(target uint32, texture uint32) {
|
||||
c.fnBindTexture.Invoke(target, c.textures.get(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
c.fnBlendEquationSeparate.Invoke(modeRGB, modeAlpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
c.fnBlendFuncSeparate.Invoke(srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferInit(target uint32, size int, usage uint32) {
|
||||
c.fnBufferData.Invoke(target, size, usage)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferSubData(target uint32, offset int, data []byte) {
|
||||
l := len(data)
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(l, data)
|
||||
if c.webGL2 {
|
||||
c.fnBufferSubData.Invoke(target, offset, arr, 0, l)
|
||||
} else {
|
||||
c.fnBufferSubData.Invoke(target, offset, arr.Call("subarray", 0, l))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) CheckFramebufferStatus(target uint32) uint32 {
|
||||
return uint32(c.fnCheckFramebufferStatus.Invoke(target).Int())
|
||||
}
|
||||
|
||||
func (c *defaultContext) Clear(mask uint32) {
|
||||
c.fnClear.Invoke(mask)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ColorMask(red, green, blue, alpha bool) {
|
||||
c.fnColorMask.Invoke(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CompileShader(shader uint32) {
|
||||
c.fnCompileShader.Invoke(c.shaders.get(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateBuffer() uint32 {
|
||||
return c.buffers.create(c.fnCreateBuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateFramebuffer() uint32 {
|
||||
return c.framebuffers.create(c.fnCreateFramebuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateProgram() uint32 {
|
||||
return c.programs.create(c.fnCreateProgram.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateRenderbuffer() uint32 {
|
||||
return c.renderbuffers.create(c.fnCreateRenderbuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateShader(xtype uint32) uint32 {
|
||||
return c.shaders.create(c.fnCreateShader.Invoke(xtype))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateTexture() uint32 {
|
||||
return c.textures.create(c.fnCreateTexture.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteBuffer(buffer uint32) {
|
||||
c.fnDeleteBuffer.Invoke(c.buffers.get(buffer))
|
||||
c.buffers.delete(buffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteFramebuffer(framebuffer uint32) {
|
||||
c.fnDeleteFramebuffer.Invoke(c.framebuffers.get(framebuffer))
|
||||
c.framebuffers.delete(framebuffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteProgram(program uint32) {
|
||||
c.fnDeleteProgram.Invoke(c.programs.get(program))
|
||||
c.programs.delete(program)
|
||||
delete(c.uniformLocations, program)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteRenderbuffer(renderbuffer uint32) {
|
||||
c.fnDeleteRenderbuffer.Invoke(c.renderbuffers.get(renderbuffer))
|
||||
c.renderbuffers.delete(renderbuffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteShader(shader uint32) {
|
||||
c.fnDeleteShader.Invoke(c.shaders.get(shader))
|
||||
c.shaders.delete(shader)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteTexture(texture uint32) {
|
||||
c.fnDeleteTexture.Invoke(c.textures.get(texture))
|
||||
c.textures.delete(texture)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Disable(cap uint32) {
|
||||
c.fnDisable.Invoke(cap)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DisableVertexAttribArray(index uint32) {
|
||||
c.fnDisableVertexAttribArray.Invoke(index)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
|
||||
c.fnDrawElements.Invoke(mode, count, xtype, offset)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Enable(cap uint32) {
|
||||
c.fnEnable.Invoke(cap)
|
||||
}
|
||||
|
||||
func (c *defaultContext) EnableVertexAttribArray(index uint32) {
|
||||
c.fnEnableVertexAttribArray.Invoke(index)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Flush() {
|
||||
c.fnFlush.Invoke()
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
c.fnFramebufferRenderbuffer.Invoke(target, attachment, renderbuffertarget, c.renderbuffers.get(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
|
||||
c.fnFramebufferTexture2D.Invoke(target, attachment, textarget, c.textures.get(texture), level)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetError() uint32 {
|
||||
return uint32(c.fnGetError.Invoke().Int())
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
ret := c.fnGetParameter.Invoke(pname)
|
||||
switch pname {
|
||||
case FRAMEBUFFER_BINDING:
|
||||
id, ok := c.framebuffers.getID(ret)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return int(id)
|
||||
case MAX_TEXTURE_SIZE:
|
||||
return ret.Int()
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected pname at GetInteger: %d", pname))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
return c.fnGetProgramInfoLog.Invoke(c.programs.get(program)).String()
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
v := c.fnGetProgramParameter.Invoke(c.programs.get(program), pname)
|
||||
switch v.Type() {
|
||||
case js.TypeNumber:
|
||||
return v.Int()
|
||||
case js.TypeBoolean:
|
||||
if v.Bool() {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected return type at GetProgrami: %v", v))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
return c.fnGetShaderInfoLog.Invoke(c.shaders.get(shader)).String()
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderi(shader uint32, pname uint32) int {
|
||||
v := c.fnGetShaderParameter.Invoke(c.shaders.get(shader), pname)
|
||||
switch v.Type() {
|
||||
case js.TypeNumber:
|
||||
return v.Int()
|
||||
case js.TypeBoolean:
|
||||
if v.Bool() {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected return type at GetShaderi: %v", v))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
location := c.fnGetUniformLocation.Invoke(c.programs.get(program), name)
|
||||
if c.uniformLocations == nil {
|
||||
c.uniformLocations = map[uint32]*values{}
|
||||
}
|
||||
vs, ok := c.uniformLocations[program]
|
||||
if !ok {
|
||||
vs = &values{}
|
||||
c.uniformLocations[program] = vs
|
||||
}
|
||||
idx := vs.getOrCreate(location)
|
||||
return int32((program << 5) | idx)
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsFramebuffer(framebuffer uint32) bool {
|
||||
return c.fnIsFramebuffer.Invoke(c.framebuffers.get(framebuffer)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsProgram(program uint32) bool {
|
||||
return c.fnIsProgram.Invoke(c.programs.get(program)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsRenderbuffer(renderbuffer uint32) bool {
|
||||
return c.fnIsRenderbuffer.Invoke(c.renderbuffers.get(renderbuffer)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsTexture(texture uint32) bool {
|
||||
return c.fnIsTexture.Invoke(c.textures.get(texture)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) LinkProgram(program uint32) {
|
||||
c.fnLinkProgram.Invoke(c.programs.get(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) PixelStorei(pname uint32, param int32) {
|
||||
c.fnPixelStorei.Invoke(pname, param)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
|
||||
if dst == nil {
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, 0)
|
||||
return
|
||||
}
|
||||
p := jsutil.TemporaryUint8ArrayFromUint8Slice(len(dst), nil)
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, p)
|
||||
js.CopyBytesToGo(dst, p)
|
||||
}
|
||||
|
||||
func (c *defaultContext) RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32) {
|
||||
c.fnRenderbufferStorage.Invoke(target, internalFormat, width, height)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Scissor(x, y, width, height int32) {
|
||||
c.fnScissor.Invoke(x, y, width, height)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ShaderSource(shader uint32, xstring string) {
|
||||
c.fnShaderSource.Invoke(c.shaders.get(shader), xstring)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilFunc(func_ uint32, ref int32, mask uint32) {
|
||||
c.fnStencilFunc.Invoke(func_, ref, mask)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilOp(sfail, dpfail, dppass uint32) {
|
||||
c.fnStencilOp.Invoke(sfail, dpfail, dppass)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
if pixels != nil {
|
||||
panic("gl: TexImage2D with non-nil pixels is not implemented")
|
||||
}
|
||||
c.fnTexImage2D.Invoke(target, level, internalformat, width, height, 0, format, xtype, nil)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
c.fnTexParameteri.Invoke(target, pname, param)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(len(pixels), pixels)
|
||||
if c.webGL2 {
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView pixels, srcOffset);
|
||||
c.fnTexSubImage2D.Invoke(target, level, xoffset, yoffset, width, height, format, xtype, arr, 0)
|
||||
} else {
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView? pixels);
|
||||
c.fnTexSubImage2D.Invoke(target, level, xoffset, yoffset, width, height, format, xtype, arr)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniform1fv.Invoke(l, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniform1fv.Invoke(l, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1i(location int32, v0 int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
c.fnUniform1i.Invoke(l, v0)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniform1iv.Invoke(l, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniform1iv.Invoke(l, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniform2fv.Invoke(l, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniform2fv.Invoke(l, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniform3fv.Invoke(l, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniform3fv.Invoke(l, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniform4fv.Invoke(l, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniform4fv.Invoke(l, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniformMatrix2fv.Invoke(l, false, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniformMatrix2fv.Invoke(l, false, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix3fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniformMatrix3fv.Invoke(l, false, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniformMatrix3fv.Invoke(l, false, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix4fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
if c.webGL2 {
|
||||
c.fnUniformMatrix4fv.Invoke(l, false, arr, 0, len(value))
|
||||
} else {
|
||||
c.fnUniformMatrix4fv.Invoke(l, false, arr.Call("subarray", 0, len(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) UseProgram(program uint32) {
|
||||
c.fnUseProgram.Invoke(c.programs.get(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
|
||||
c.fnVertexAttribPointer.Invoke(index, size, xtype, normalized, stride, offset)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Viewport(x int32, y int32, width int32, height int32) {
|
||||
c.fnViewport.Invoke(x, y, width, height)
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
// Copyright 2021 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 opengl
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
type jsGL struct {
|
||||
activeTexture js.Value
|
||||
attachShader js.Value
|
||||
bindAttribLocation js.Value
|
||||
bindBuffer js.Value
|
||||
bindFramebuffer js.Value
|
||||
bindRenderbuffer js.Value
|
||||
bindTexture js.Value
|
||||
blendEquationSeparate js.Value
|
||||
blendFuncSeparate js.Value
|
||||
bufferData js.Value
|
||||
bufferSubData js.Value
|
||||
checkFramebufferStatus js.Value
|
||||
clear js.Value
|
||||
colorMask js.Value
|
||||
compileShader js.Value
|
||||
createBuffer js.Value
|
||||
createFramebuffer js.Value
|
||||
createProgram js.Value
|
||||
createRenderbuffer js.Value
|
||||
createShader js.Value
|
||||
createTexture js.Value
|
||||
deleteBuffer js.Value
|
||||
deleteFramebuffer js.Value
|
||||
deleteProgram js.Value
|
||||
deleteRenderbuffer js.Value
|
||||
deleteShader js.Value
|
||||
deleteTexture js.Value
|
||||
disable js.Value
|
||||
disableVertexAttribArray js.Value
|
||||
drawElements js.Value
|
||||
enable js.Value
|
||||
enableVertexAttribArray js.Value
|
||||
framebufferRenderbuffer js.Value
|
||||
framebufferTexture2D js.Value
|
||||
flush js.Value
|
||||
getExtension js.Value
|
||||
getParameter js.Value
|
||||
getProgramInfoLog js.Value
|
||||
getProgramParameter js.Value
|
||||
getShaderInfoLog js.Value
|
||||
getShaderParameter js.Value
|
||||
getUniformLocation js.Value
|
||||
isContextLost js.Value
|
||||
isFramebuffer js.Value
|
||||
isProgram js.Value
|
||||
isRenderbuffer js.Value
|
||||
isTexture js.Value
|
||||
linkProgram js.Value
|
||||
pixelStorei js.Value
|
||||
readPixels js.Value
|
||||
renderbufferStorage js.Value
|
||||
scissor js.Value
|
||||
shaderSource js.Value
|
||||
stencilFunc js.Value
|
||||
stencilMask js.Value
|
||||
stencilOp js.Value
|
||||
texImage2D js.Value
|
||||
texSubImage2D js.Value
|
||||
texParameteri js.Value
|
||||
uniform1fv js.Value
|
||||
uniform1i js.Value
|
||||
uniform1iv js.Value
|
||||
uniform2fv js.Value
|
||||
uniform3fv js.Value
|
||||
uniform4fv js.Value
|
||||
uniformMatrix2fv js.Value
|
||||
uniformMatrix3fv js.Value
|
||||
uniformMatrix4fv js.Value
|
||||
useProgram js.Value
|
||||
vertexAttribPointer js.Value
|
||||
viewport js.Value
|
||||
}
|
||||
|
||||
func (c *context) newJSGL(v js.Value) *jsGL {
|
||||
// Passing a Go string to the JS world is expensive. This causes conversion to UTF-16 (#1438).
|
||||
// In order to reduce the cost when calling functions, create the function objects by bind and use them.
|
||||
g := &jsGL{
|
||||
activeTexture: v.Get("activeTexture").Call("bind", v),
|
||||
attachShader: v.Get("attachShader").Call("bind", v),
|
||||
bindAttribLocation: v.Get("bindAttribLocation").Call("bind", v),
|
||||
bindBuffer: v.Get("bindBuffer").Call("bind", v),
|
||||
bindFramebuffer: v.Get("bindFramebuffer").Call("bind", v),
|
||||
bindRenderbuffer: v.Get("bindRenderbuffer").Call("bind", v),
|
||||
bindTexture: v.Get("bindTexture").Call("bind", v),
|
||||
blendEquationSeparate: v.Get("blendEquationSeparate").Call("bind", v),
|
||||
blendFuncSeparate: v.Get("blendFuncSeparate").Call("bind", v),
|
||||
bufferData: v.Get("bufferData").Call("bind", v),
|
||||
bufferSubData: v.Get("bufferSubData").Call("bind", v),
|
||||
checkFramebufferStatus: v.Get("checkFramebufferStatus").Call("bind", v),
|
||||
clear: v.Get("clear").Call("bind", v),
|
||||
colorMask: v.Get("colorMask").Call("bind", v),
|
||||
compileShader: v.Get("compileShader").Call("bind", v),
|
||||
createBuffer: v.Get("createBuffer").Call("bind", v),
|
||||
createFramebuffer: v.Get("createFramebuffer").Call("bind", v),
|
||||
createProgram: v.Get("createProgram").Call("bind", v),
|
||||
createRenderbuffer: v.Get("createRenderbuffer").Call("bind", v),
|
||||
createShader: v.Get("createShader").Call("bind", v),
|
||||
createTexture: v.Get("createTexture").Call("bind", v),
|
||||
deleteBuffer: v.Get("deleteBuffer").Call("bind", v),
|
||||
deleteFramebuffer: v.Get("deleteFramebuffer").Call("bind", v),
|
||||
deleteProgram: v.Get("deleteProgram").Call("bind", v),
|
||||
deleteRenderbuffer: v.Get("deleteRenderbuffer").Call("bind", v),
|
||||
deleteShader: v.Get("deleteShader").Call("bind", v),
|
||||
deleteTexture: v.Get("deleteTexture").Call("bind", v),
|
||||
disable: v.Get("disable").Call("bind", v),
|
||||
disableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
|
||||
drawElements: v.Get("drawElements").Call("bind", v),
|
||||
enable: v.Get("enable").Call("bind", v),
|
||||
enableVertexAttribArray: v.Get("enableVertexAttribArray").Call("bind", v),
|
||||
framebufferRenderbuffer: v.Get("framebufferRenderbuffer").Call("bind", v),
|
||||
framebufferTexture2D: v.Get("framebufferTexture2D").Call("bind", v),
|
||||
flush: v.Get("flush").Call("bind", v),
|
||||
getParameter: v.Get("getParameter").Call("bind", v),
|
||||
getProgramInfoLog: v.Get("getProgramInfoLog").Call("bind", v),
|
||||
getProgramParameter: v.Get("getProgramParameter").Call("bind", v),
|
||||
getShaderInfoLog: v.Get("getShaderInfoLog").Call("bind", v),
|
||||
getShaderParameter: v.Get("getShaderParameter").Call("bind", v),
|
||||
getUniformLocation: v.Get("getUniformLocation").Call("bind", v),
|
||||
isContextLost: v.Get("isContextLost").Call("bind", v),
|
||||
isFramebuffer: v.Get("isFramebuffer").Call("bind", v),
|
||||
isProgram: v.Get("isProgram").Call("bind", v),
|
||||
isRenderbuffer: v.Get("isRenderbuffer").Call("bind", v),
|
||||
isTexture: v.Get("isTexture").Call("bind", v),
|
||||
linkProgram: v.Get("linkProgram").Call("bind", v),
|
||||
pixelStorei: v.Get("pixelStorei").Call("bind", v),
|
||||
readPixels: v.Get("readPixels").Call("bind", v),
|
||||
renderbufferStorage: v.Get("renderbufferStorage").Call("bind", v),
|
||||
scissor: v.Get("scissor").Call("bind", v),
|
||||
shaderSource: v.Get("shaderSource").Call("bind", v),
|
||||
stencilFunc: v.Get("stencilFunc").Call("bind", v),
|
||||
stencilMask: v.Get("stencilMask").Call("bind", v),
|
||||
stencilOp: v.Get("stencilOp").Call("bind", v),
|
||||
texImage2D: v.Get("texImage2D").Call("bind", v),
|
||||
texSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
||||
texParameteri: v.Get("texParameteri").Call("bind", v),
|
||||
uniform1fv: v.Get("uniform1fv").Call("bind", v),
|
||||
uniform1i: v.Get("uniform1i").Call("bind", v),
|
||||
uniform1iv: v.Get("uniform1iv").Call("bind", v),
|
||||
uniform2fv: v.Get("uniform2fv").Call("bind", v),
|
||||
uniform3fv: v.Get("uniform3fv").Call("bind", v),
|
||||
uniform4fv: v.Get("uniform4fv").Call("bind", v),
|
||||
uniformMatrix2fv: v.Get("uniformMatrix2fv").Call("bind", v),
|
||||
uniformMatrix3fv: v.Get("uniformMatrix3fv").Call("bind", v),
|
||||
uniformMatrix4fv: v.Get("uniformMatrix4fv").Call("bind", v),
|
||||
useProgram: v.Get("useProgram").Call("bind", v),
|
||||
vertexAttribPointer: v.Get("vertexAttribPointer").Call("bind", v),
|
||||
viewport: v.Get("viewport").Call("bind", v),
|
||||
}
|
||||
if !c.usesWebGL2() {
|
||||
g.getExtension = v.Get("getExtension").Call("bind", v)
|
||||
}
|
||||
return g
|
||||
}
|
@ -44,10 +44,10 @@ func (i *Image) Dispose() {
|
||||
if i.framebuffer != nil {
|
||||
i.framebuffer.delete(&i.graphics.context)
|
||||
}
|
||||
if !i.texture.equal(*new(textureNative)) {
|
||||
if i.texture != 0 {
|
||||
i.graphics.context.deleteTexture(i.texture)
|
||||
}
|
||||
if !i.stencil.equal(*new(renderbufferNative)) {
|
||||
if i.stencil != 0 {
|
||||
i.graphics.context.deleteRenderbuffer(i.stencil)
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ func (i *Image) ensureFramebuffer() error {
|
||||
}
|
||||
|
||||
func (i *Image) ensureStencilBuffer() error {
|
||||
if !i.stencil.equal(*new(renderbufferNative)) {
|
||||
if i.stencil != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -14,31 +14,28 @@
|
||||
|
||||
package opengl
|
||||
|
||||
// Since js.Object (Program) can't be keys of a map, use integers (programID) instead.
|
||||
|
||||
type locationCache struct {
|
||||
uniformLocationCache map[programID]map[string]uniformLocation
|
||||
uniformLocationCache map[program]map[string]uniformLocation
|
||||
}
|
||||
|
||||
func newLocationCache() *locationCache {
|
||||
return &locationCache{
|
||||
uniformLocationCache: map[programID]map[string]uniformLocation{},
|
||||
uniformLocationCache: map[program]map[string]uniformLocation{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *locationCache) GetUniformLocation(context *context, p program, location string) uniformLocation {
|
||||
id := getProgramID(p)
|
||||
if _, ok := c.uniformLocationCache[id]; !ok {
|
||||
c.uniformLocationCache[id] = map[string]uniformLocation{}
|
||||
if _, ok := c.uniformLocationCache[p]; !ok {
|
||||
c.uniformLocationCache[p] = map[string]uniformLocation{}
|
||||
}
|
||||
l, ok := c.uniformLocationCache[id][location]
|
||||
l, ok := c.uniformLocationCache[p][location]
|
||||
if !ok {
|
||||
l = context.getUniformLocationImpl(p, location)
|
||||
c.uniformLocationCache[id][location] = l
|
||||
c.uniformLocationCache[p][location] = l
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (c *locationCache) deleteProgram(p program) {
|
||||
delete(c.uniformLocationCache, getProgramID(p))
|
||||
delete(c.uniformLocationCache, p)
|
||||
}
|
||||
|
@ -127,19 +127,14 @@ type openGLState struct {
|
||||
lastActiveTexture int
|
||||
}
|
||||
|
||||
var (
|
||||
zeroBuffer buffer
|
||||
zeroProgram program
|
||||
)
|
||||
|
||||
// reset resets or initializes the OpenGL state.
|
||||
func (s *openGLState) reset(context *context) error {
|
||||
if err := context.reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.lastProgram = zeroProgram
|
||||
context.useProgram(zeroProgram)
|
||||
s.lastProgram = 0
|
||||
context.useProgram(0)
|
||||
for key := range s.lastUniforms {
|
||||
delete(s.lastUniforms, key)
|
||||
}
|
||||
@ -147,10 +142,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 runtime.GOOS != "js" {
|
||||
if !s.arrayBuffer.equal(zeroBuffer) {
|
||||
if s.arrayBuffer != 0 {
|
||||
context.deleteBuffer(s.arrayBuffer)
|
||||
}
|
||||
if !s.elementArrayBuffer.equal(zeroBuffer) {
|
||||
if s.elementArrayBuffer != 0 {
|
||||
context.deleteBuffer(s.elementArrayBuffer)
|
||||
}
|
||||
}
|
||||
@ -203,9 +198,9 @@ func (g *Graphics) textureVariableName(idx int) string {
|
||||
|
||||
// useProgram uses the program (programTexture).
|
||||
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderImageCount]textureVariable) error {
|
||||
if !g.state.lastProgram.equal(program) {
|
||||
if g.state.lastProgram != program {
|
||||
g.context.useProgram(program)
|
||||
if g.state.lastProgram.equal(zeroProgram) {
|
||||
if g.state.lastProgram == 0 {
|
||||
theArrayBufferLayout.enable(&g.context)
|
||||
g.context.bindArrayBuffer(g.state.arrayBuffer)
|
||||
g.context.bindElementArrayBuffer(g.state.elementArrayBuffer)
|
||||
@ -251,7 +246,7 @@ loop:
|
||||
// If the texture is already bound, set the texture variable to point to the texture.
|
||||
// Rebinding the same texture seems problematic (#1193).
|
||||
for _, at := range g.activatedTextures {
|
||||
if t.native.equal(at.textureNative) {
|
||||
if t.native == at.textureNative {
|
||||
g.context.uniformInt(program, g.textureVariableName(i), at.index)
|
||||
continue loop
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user