From ba8238ba6651273f3689838674ae4a3a0e73b69a Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Wed, 27 Feb 2019 15:46:08 +0100 Subject: [PATCH] canvas bounds update fix, gomobile example works again --- backend/gogl/gogl.go | 92 +++++++++++++++++++---------------- backend/xmobile/xmobile.go | 92 +++++++++++++++++++---------------- examples/gomobile/gomobile.go | 30 +++++++----- 3 files changed, 119 insertions(+), 95 deletions(-) diff --git a/backend/gogl/gogl.go b/backend/gogl/gogl.go index 350e40e..a775445 100644 --- a/backend/gogl/gogl.go +++ b/backend/gogl/gogl.go @@ -236,14 +236,14 @@ func NewOffscreen(w, h int, alpha bool) (*GoGLBackendOffscreen, error) { } bo := &GoGLBackendOffscreen{} bo.offscrBuf.alpha = alpha + bo.offscrImg.flip = true b.activateFn = func() { b.enableTextureRenderTarget(&bo.offscrBuf) - gl.Viewport(0, 0, int32(b.w), int32(b.h)) + gl.Viewport(0, 0, int32(bo.GoGLBackend.w), int32(bo.GoGLBackend.h)) bo.offscrImg.w = bo.offscrBuf.w bo.offscrImg.h = bo.offscrBuf.h bo.offscrImg.tex = bo.offscrBuf.tex - bo.offscrImg.flip = true } b.disableTextureRenderTarget = func() { b.enableTextureRenderTarget(&bo.offscrBuf) @@ -270,6 +270,9 @@ func (b *GoGLBackend) SetBounds(x, y, w, h int) { // SetBounds updates the size of the offscreen texture func (b *GoGLBackendOffscreen) SetBounds(w, h int) { b.GoGLBackend.SetBounds(0, 0, w, h) + b.enableTextureRenderTarget(&b.offscrBuf) + b.offscrImg.w = b.offscrBuf.w + b.offscrImg.h = b.offscrBuf.h } func (b *GoGLBackend) Size() (int, int) { @@ -452,48 +455,53 @@ func (b *GoGLBackend) useAlphaShader(style *backendbase.FillStyle, alphaTexSlot } func (b *GoGLBackend) enableTextureRenderTarget(offscr *offscreenBuffer) { - if offscr.w != b.w || offscr.h != b.h { - if offscr.w != 0 && offscr.h != 0 { - gl.DeleteTextures(1, &offscr.tex) - gl.DeleteFramebuffers(1, &offscr.frameBuf) - gl.DeleteRenderbuffers(1, &offscr.renderStencilBuf) - } - offscr.w = b.w - offscr.h = b.h - - gl.ActiveTexture(gl.TEXTURE0) - gl.GenTextures(1, &offscr.tex) - gl.BindTexture(gl.TEXTURE_2D, offscr.tex) - // todo do non-power-of-two textures work everywhere? - if offscr.alpha { - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(b.w), int32(b.h), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) - } else { - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(b.w), int32(b.h), 0, gl.RGB, gl.UNSIGNED_BYTE, nil) - } - 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) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) - - gl.GenFramebuffers(1, &offscr.frameBuf) - gl.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) - - gl.GenRenderbuffers(1, &offscr.renderStencilBuf) - gl.BindRenderbuffer(gl.RENDERBUFFER, offscr.renderStencilBuf) - gl.RenderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, int32(b.w), int32(b.h)) - gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, offscr.renderStencilBuf) - - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, offscr.tex, 0) - - if err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); err != gl.FRAMEBUFFER_COMPLETE { - // todo this should maybe not panic - panic(fmt.Sprintf("Failed to set up framebuffer for offscreen texture: %x", err)) - } - - gl.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) - } else { + if offscr.w == b.w && offscr.h == b.h { gl.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) + return } + + if b.w == 0 || b.h == 0 { + return + } + + if offscr.w != 0 && offscr.h != 0 { + gl.DeleteTextures(1, &offscr.tex) + gl.DeleteFramebuffers(1, &offscr.frameBuf) + gl.DeleteRenderbuffers(1, &offscr.renderStencilBuf) + } + offscr.w = b.w + offscr.h = b.h + + gl.ActiveTexture(gl.TEXTURE0) + gl.GenTextures(1, &offscr.tex) + gl.BindTexture(gl.TEXTURE_2D, offscr.tex) + // todo do non-power-of-two textures work everywhere? + if offscr.alpha { + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(b.w), int32(b.h), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) + } else { + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(b.w), int32(b.h), 0, gl.RGB, gl.UNSIGNED_BYTE, nil) + } + 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) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) + + gl.GenFramebuffers(1, &offscr.frameBuf) + gl.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) + + gl.GenRenderbuffers(1, &offscr.renderStencilBuf) + gl.BindRenderbuffer(gl.RENDERBUFFER, offscr.renderStencilBuf) + gl.RenderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, int32(b.w), int32(b.h)) + gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, offscr.renderStencilBuf) + + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, offscr.tex, 0) + + if err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); err != gl.FRAMEBUFFER_COMPLETE { + // todo this should maybe not panic + panic(fmt.Sprintf("Failed to set up framebuffer for offscreen texture: %x", err)) + } + + gl.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) } type vec [2]float64 diff --git a/backend/xmobile/xmobile.go b/backend/xmobile/xmobile.go index d2010df..f18642b 100755 --- a/backend/xmobile/xmobile.go +++ b/backend/xmobile/xmobile.go @@ -239,14 +239,14 @@ func NewOffscreen(glctx gl.Context, w, h int, alpha bool) (*XMobileBackendOffscr } bo := &XMobileBackendOffscreen{} bo.offscrBuf.alpha = alpha + bo.offscrImg.flip = true b.activateFn = func() { b.enableTextureRenderTarget(&bo.offscrBuf) - b.glctx.Viewport(0, 0, b.w, b.h) + b.glctx.Viewport(0, 0, bo.XMobileBackend.w, bo.XMobileBackend.h) bo.offscrImg.w = bo.offscrBuf.w bo.offscrImg.h = bo.offscrBuf.h bo.offscrImg.tex = bo.offscrBuf.tex - bo.offscrImg.flip = true } b.disableTextureRenderTarget = func() { b.enableTextureRenderTarget(&bo.offscrBuf) @@ -273,6 +273,9 @@ func (b *XMobileBackend) SetBounds(x, y, w, h int) { // SetBounds updates the size of the offscreen texture func (b *XMobileBackendOffscreen) SetBounds(w, h int) { b.XMobileBackend.SetBounds(0, 0, w, h) + b.enableTextureRenderTarget(&b.offscrBuf) + b.offscrImg.w = b.offscrBuf.w + b.offscrImg.h = b.offscrBuf.h } func (b *XMobileBackend) Size() (int, int) { @@ -455,48 +458,53 @@ func (b *XMobileBackend) useAlphaShader(style *backendbase.FillStyle, alphaTexSl } func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) { - if offscr.w != b.w || offscr.h != b.h { - if offscr.w != 0 && offscr.h != 0 { - b.glctx.DeleteTexture(offscr.tex) - b.glctx.DeleteFramebuffer(offscr.frameBuf) - b.glctx.DeleteRenderbuffer(offscr.renderStencilBuf) - } - offscr.w = b.w - offscr.h = b.h - - b.glctx.ActiveTexture(gl.TEXTURE0) - offscr.tex = b.glctx.CreateTexture() - b.glctx.BindTexture(gl.TEXTURE_2D, offscr.tex) - // todo do non-power-of-two textures work everywhere? - if offscr.alpha { - b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, b.w, b.h, gl.RGBA, gl.UNSIGNED_BYTE, nil) - } else { - b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, b.w, b.h, gl.RGB, gl.UNSIGNED_BYTE, nil) - } - b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) - b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) - - offscr.frameBuf = b.glctx.CreateFramebuffer() - b.glctx.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) - - offscr.renderStencilBuf = b.glctx.CreateRenderbuffer() - b.glctx.BindRenderbuffer(gl.RENDERBUFFER, offscr.renderStencilBuf) - b.glctx.RenderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, b.w, b.h) - b.glctx.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, offscr.renderStencilBuf) - - b.glctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, offscr.tex, 0) - - if err := b.glctx.CheckFramebufferStatus(gl.FRAMEBUFFER); err != gl.FRAMEBUFFER_COMPLETE { - // todo this should maybe not panic - panic(fmt.Sprintf("Failed to set up framebuffer for offscreen texture: %x", err)) - } - - b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) - } else { + if offscr.w == b.w && offscr.h == b.h { b.glctx.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) + return } + + if b.w == 0 || b.h == 0 { + return + } + + if offscr.w != 0 && offscr.h != 0 { + b.glctx.DeleteTexture(offscr.tex) + b.glctx.DeleteFramebuffer(offscr.frameBuf) + b.glctx.DeleteRenderbuffer(offscr.renderStencilBuf) + } + offscr.w = b.w + offscr.h = b.h + + b.glctx.ActiveTexture(gl.TEXTURE0) + offscr.tex = b.glctx.CreateTexture() + b.glctx.BindTexture(gl.TEXTURE_2D, offscr.tex) + // todo do non-power-of-two textures work everywhere? + if offscr.alpha { + b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, b.w, b.h, gl.RGBA, gl.UNSIGNED_BYTE, nil) + } else { + b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, b.w, b.h, gl.RGB, gl.UNSIGNED_BYTE, nil) + } + b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) + b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) + b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) + b.glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) + + offscr.frameBuf = b.glctx.CreateFramebuffer() + b.glctx.BindFramebuffer(gl.FRAMEBUFFER, offscr.frameBuf) + + offscr.renderStencilBuf = b.glctx.CreateRenderbuffer() + b.glctx.BindRenderbuffer(gl.RENDERBUFFER, offscr.renderStencilBuf) + b.glctx.RenderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, b.w, b.h) + b.glctx.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, offscr.renderStencilBuf) + + b.glctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, offscr.tex, 0) + + if err := b.glctx.CheckFramebufferStatus(gl.FRAMEBUFFER); err != gl.FRAMEBUFFER_COMPLETE { + // todo this should maybe not panic + panic(fmt.Sprintf("Failed to set up framebuffer for offscreen texture: %x", err)) + } + + b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) } type vec [2]float64 diff --git a/examples/gomobile/gomobile.go b/examples/gomobile/gomobile.go index 4fc533e..5d59041 100644 --- a/examples/gomobile/gomobile.go +++ b/examples/gomobile/gomobile.go @@ -1,11 +1,12 @@ package main import ( + "log" "math" "time" "github.com/tfriedel6/canvas" - "github.com/tfriedel6/canvas/glimpl/xmobile" + "github.com/tfriedel6/canvas/backend/xmobile" "golang.org/x/mobile/app" "golang.org/x/mobile/event/lifecycle" "golang.org/x/mobile/event/paint" @@ -16,6 +17,8 @@ import ( func main() { app.Main(func(a app.App) { var cv, painter *canvas.Canvas + var cvb *xmobilebackend.XMobileBackendOffscreen + var painterb *xmobilebackend.XMobileBackend var w, h int var glctx gl.Context @@ -24,30 +27,35 @@ func main() { case lifecycle.Event: switch e.Crosses(lifecycle.StageVisible) { case lifecycle.CrossOn: - glctx, _ = e.DrawContext.(gl.Context) - canvas.LoadGL(glimplxmobile.New(glctx)) - cv = canvas.NewOffscreen(0, 0) - painter = canvas.New(0, 0, 0, 0) + var err error + glctx = e.DrawContext.(gl.Context) + cvb, err = xmobilebackend.NewOffscreen(glctx, 0, 0, false) + if err != nil { + log.Fatalln(err) + } + painterb, err = xmobilebackend.New(glctx, 0, 0, 0, 0) + if err != nil { + log.Fatalln(err) + } + cv = canvas.New(cvb) + painter = canvas.New(painterb) a.Send(paint.Event{}) case lifecycle.CrossOff: + cvb.Delete() glctx = nil } case size.Event: w, h = e.WidthPx, e.HeightPx case paint.Event: if glctx != nil { - glctx.ClearColor(0, 0, 0, 0) - glctx.Clear(gl.COLOR_BUFFER_BIT) - - cv.SetBounds(0, 0, w, h) - painter.SetBounds(0, 0, w, h) - fw, fh := float64(w), float64(h) color := math.Sin(float64(time.Now().UnixNano())*0.000000002)*0.3 + 0.7 + cvb.SetBounds(w, h) cv.SetFillStyle(color*0.2, color*0.2, color*0.8) cv.FillRect(fw*0.25, fh*0.25, fw*0.5, fh*0.5) + painterb.SetBounds(0, 0, w, h) painter.DrawImage(cv) a.Publish()