From 0cb030619eb78036e92a838d4ad36bde7341e7d4 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Mon, 11 Jun 2018 21:47:33 +0200 Subject: [PATCH] added a function to switch to an offscreen framebuffer --- canvas.go | 80 +++++++++++++++++++++++++++++++++-------- glimpl/gogl/goglimpl.go | 30 ++++++++++++++++ openglinterface.go | 10 ++++++ 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/canvas.go b/canvas.go index b411255..0dac4d0 100644 --- a/canvas.go +++ b/canvas.go @@ -177,20 +177,25 @@ loop: const alphaTexSize = 2048 var ( - gli GL - buf uint32 - shadowBuf uint32 - alphaTex uint32 - sr *solidShader - lgr *linearGradientShader - rgr *radialGradientShader - ipr *imagePatternShader - sar *solidAlphaShader - rgar *radialGradientAlphaShader - lgar *linearGradientAlphaShader - ipar *imagePatternAlphaShader - ir *imageShader - glChan = make(chan func()) + gli GL + buf uint32 + shadowBuf uint32 + alphaTex uint32 + sr *solidShader + lgr *linearGradientShader + rgr *radialGradientShader + ipr *imagePatternShader + sar *solidAlphaShader + rgar *radialGradientAlphaShader + lgar *linearGradientAlphaShader + ipar *imagePatternAlphaShader + ir *imageShader + offScrTex uint32 + offScrW int + offScrH int + renderStencilBuf uint32 + frameBuf uint32 + glChan = make(chan func()) ) // LoadGL needs to be called once per GL context to load the GL assets @@ -509,6 +514,53 @@ func (cv *Canvas) useAlphaShader(style *drawStyle, alphaTexSlot int32) (vertexLo return sar.vertex, sar.alphaTexCoord } +func (cv *Canvas) enableTextureRenderTarget() { + if offScrW != cv.w || offScrH != cv.h { + if offScrW != 0 && offScrH != 0 { + gli.DeleteTextures(1, &offScrTex) + gli.DeleteFramebuffers(1, &frameBuf) + gli.DeleteRenderbuffers(1, &renderStencilBuf) + } + offScrW = cv.w + offScrH = cv.h + + gli.GenTextures(1, &offScrTex) + gli.BindTexture(gl_TEXTURE_2D, offScrTex) + // todo do non-power-of-two textures work everywhere? + gli.TexImage2D(gl_TEXTURE_2D, 0, gl_RGB, int32(cv.w), int32(cv.h), 0, gl_RGB, gl_UNSIGNED_BYTE, nil) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_NEAREST) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_NEAREST) + + gli.GenFramebuffers(1, &frameBuf) + gli.BindFramebuffer(gl_FRAMEBUFFER, frameBuf) + + gli.GenRenderbuffers(1, &renderStencilBuf) + gli.BindRenderbuffer(gl_RENDERBUFFER, renderStencilBuf) + gli.RenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_STENCIL, int32(cv.w), int32(cv.h)) + gli.FramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_STENCIL_ATTACHMENT, gl_RENDERBUFFER, renderStencilBuf) + + gli.FramebufferTexture(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, offScrTex, 0) + + if gli.CheckFramebufferStatus(gl_FRAMEBUFFER) != gl_FRAMEBUFFER_COMPLETE { + // todo this should maybe not panic + panic("Failed to set up framebuffer for offscreen texture") + } + + gli.Clear(gl_COLOR_BUFFER_BIT | gl_STENCIL_BUFFER_BIT) + } else { + gli.BindFramebuffer(gl_FRAMEBUFFER, frameBuf) + } +} + +func (cv *Canvas) disableTextureRenderTarget() { + gli.BindFramebuffer(gl_FRAMEBUFFER, 0) +} + +func (cv *Canvas) renderOffscreenTexture() { + img := Image{w: cv.w, h: cv.h, tex: offScrTex} + cv.DrawImage(&img, 0, 0, cv.fw, cv.fh) +} + // SetLineWidth sets the line width for any line drawing calls func (cv *Canvas) SetLineWidth(width float64) { if width < 0 { diff --git a/glimpl/gogl/goglimpl.go b/glimpl/gogl/goglimpl.go index f1a2a62..e3382a0 100644 --- a/glimpl/gogl/goglimpl.go +++ b/glimpl/gogl/goglimpl.go @@ -24,6 +24,12 @@ func (_ GLImpl) AttachShader(program uint32, shader uint32) { func (_ GLImpl) BindBuffer(target uint32, buffer uint32) { gl.BindBuffer(target, buffer) } +func (_ GLImpl) BindFramebuffer(target uint32, framebuffer uint32) { + gl.BindFramebuffer(target, framebuffer) +} +func (_ GLImpl) BindRenderbuffer(target uint32, renderbuffer uint32) { + gl.BindRenderbuffer(target, renderbuffer) +} func (_ GLImpl) BindTexture(target uint32, texture uint32) { gl.BindTexture(target, texture) } @@ -33,6 +39,9 @@ func (_ GLImpl) BlendFunc(sfactor uint32, dfactor uint32) { func (_ GLImpl) BufferData(target uint32, size int, data unsafe.Pointer, usage uint32) { gl.BufferData(target, size, data, usage) } +func (_ GLImpl) CheckFramebufferStatus(target uint32) uint32 { + return gl.CheckFramebufferStatus(target) +} func (_ GLImpl) Clear(mask uint32) { gl.Clear(mask) } @@ -54,6 +63,12 @@ func (_ GLImpl) CreateShader(xtype uint32) uint32 { func (_ GLImpl) DeleteShader(shader uint32) { gl.DeleteShader(shader) } +func (_ GLImpl) DeleteFramebuffers(n int32, framebuffers *uint32) { + gl.DeleteFramebuffers(n, framebuffers) +} +func (_ GLImpl) DeleteRenderbuffers(n int32, renderbuffers *uint32) { + gl.DeleteRenderbuffers(n, renderbuffers) +} func (_ GLImpl) DeleteTextures(n int32, textures *uint32) { gl.DeleteTextures(n, textures) } @@ -72,9 +87,21 @@ func (_ GLImpl) Enable(cap uint32) { func (_ GLImpl) EnableVertexAttribArray(index uint32) { gl.EnableVertexAttribArray(index) } +func (_ GLImpl) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) { + gl.FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) +} +func (_ GLImpl) FramebufferTexture(target uint32, attachment uint32, texture uint32, level int32) { + gl.FramebufferTexture(target, attachment, texture, level) +} func (_ GLImpl) GenBuffers(n int32, buffers *uint32) { gl.GenBuffers(n, buffers) } +func (_ GLImpl) GenFramebuffers(n int32, framebuffers *uint32) { + gl.GenFramebuffers(n, framebuffers) +} +func (_ GLImpl) GenRenderbuffers(n int32, renderbuffers *uint32) { + gl.GenRenderbuffers(n, renderbuffers) +} func (_ GLImpl) GenTextures(n int32, textures *uint32) { gl.GenTextures(n, textures) } @@ -119,6 +146,9 @@ func (_ GLImpl) GetUniformLocation(program uint32, name string) int32 { func (_ GLImpl) LinkProgram(program uint32) { gl.LinkProgram(program) } +func (_ GLImpl) RenderbufferStorage(target uint32, internalformat uint32, width int32, height int32) { + gl.RenderbufferStorage(target, internalformat, width, height) +} func (_ GLImpl) ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) { gl.ReadPixels(x, y, width, height, format, xtype, pixels) } diff --git a/openglinterface.go b/openglinterface.go index 9bd4cbd..39786ce 100644 --- a/openglinterface.go +++ b/openglinterface.go @@ -797,9 +797,12 @@ type GL interface { ActiveTexture(texture uint32) AttachShader(program uint32, shader uint32) BindBuffer(target uint32, buffer uint32) + BindFramebuffer(target uint32, framebuffer uint32) + BindRenderbuffer(target uint32, renderbuffer uint32) BindTexture(target uint32, texture uint32) BlendFunc(sfactor uint32, dfactor uint32) BufferData(target uint32, size int, data unsafe.Pointer, usage uint32) + CheckFramebufferStatus(target uint32) uint32 Clear(mask uint32) ClearColor(red float32, green float32, blue float32, alpha float32) ColorMask(red bool, green bool, blue bool, alpha bool) @@ -807,13 +810,19 @@ type GL interface { CreateProgram() uint32 CreateShader(xtype uint32) uint32 DeleteShader(shader uint32) + DeleteFramebuffers(n int32, framebuffers *uint32) + DeleteRenderbuffers(n int32, renderbuffers *uint32) DeleteTextures(n int32, textures *uint32) Disable(cap uint32) DisableVertexAttribArray(index uint32) DrawArrays(mode uint32, first int32, count int32) Enable(cap uint32) EnableVertexAttribArray(index uint32) + FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) + FramebufferTexture(target uint32, attachment uint32, texture uint32, level int32) GenBuffers(n int32, buffers *uint32) + GenFramebuffers(n int32, framebuffers *uint32) + GenRenderbuffers(n int32, renderbuffers *uint32) GenTextures(n int32, textures *uint32) GenerateMipmap(target uint32) GetAttribLocation(program uint32, name string) int32 @@ -825,6 +834,7 @@ type GL interface { GetUniformLocation(program uint32, name string) int32 LinkProgram(program uint32) ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) + RenderbufferStorage(target uint32, internalformat uint32, width int32, height int32) Scissor(x int32, y int32, width int32, height int32) ShaderSource(shader uint32, source string) StencilFunc(xfunc uint32, ref int32, mask uint32)