// newFBO will generate a new Frame Buffer Object for use with the canvas func newFBO(texture gl.Texture) (gl.Framebuffer, uint32) { // get currently bound fbo to reset to it later current_fbo := gl.GetBoundFramebuffer() framebuffer := gl.CreateFramebuffer() gl.BindFramebuffer(gl.FRAMEBUFFER, framebuffer) if texture.Valid() { gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0) // Initialize the texture to transparent black. gl.ClearColor(0.0, 0.0, 0.0, 0.0) gl.Clear(gl.COLOR_BUFFER_BIT) } status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER) // unbind framebuffer gl.BindFramebuffer(gl.FRAMEBUFFER, current_fbo) return framebuffer, uint32(status) }
// checkCreateStencil if a stencil is set on a canvas then we need to create // some buffers to handle this. func (canvas *Canvas) checkCreateStencil() bool { // Do nothing if we've already created the stencil buffer. if canvas.depth_stencil.Valid() { return true } if gl_state.currentCanvas != canvas { gl.BindFramebuffer(gl.FRAMEBUFFER, canvas.fbo) } format := gl.STENCIL_INDEX8 attachment := gl.STENCIL_ATTACHMENT canvas.depth_stencil = gl.CreateRenderbuffer() gl.BindRenderbuffer(gl.RENDERBUFFER, canvas.depth_stencil) gl.RenderbufferStorage(gl.RENDERBUFFER, gl.Enum(format), int(canvas.width), int(canvas.height)) // Attach the stencil buffer to the framebuffer object. gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.Enum(attachment), gl.RENDERBUFFER, canvas.depth_stencil) gl.BindRenderbuffer(gl.RENDERBUFFER, gl.Renderbuffer{}) success := (gl.CheckFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) // We don't want the stencil buffer filled with garbage. if success { gl.Clear(gl.STENCIL_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) } else { gl.DeleteRenderbuffer(canvas.depth_stencil) canvas.depth_stencil = gl.Renderbuffer{} } if gl_state.currentCanvas != nil && gl_state.currentCanvas != canvas { gl.BindFramebuffer(gl.FRAMEBUFFER, gl_state.currentCanvas.fbo) } else if gl_state.currentCanvas == nil { gl.BindFramebuffer(gl.FRAMEBUFFER, getDefaultFBO()) } return success }
// stopGrab will bind the context back to the default framebuffer and set back // all the settings func (canvas *Canvas) stopGrab(switchingToOtherCanvas bool) error { // i am not grabbing. leave me alone if gl_state.currentCanvas != canvas { return nil } gl_state.projectionStack.Pop() if !switchingToOtherCanvas { // bind system framebuffer. gl_state.currentCanvas = nil gl.BindFramebuffer(gl.FRAMEBUFFER, getDefaultFBO()) SetViewport(canvas.systemViewport[0], canvas.systemViewport[1], canvas.systemViewport[2], canvas.systemViewport[3]) } return nil }
// startGrab will bind this canvas to grab all drawing operations // multiple canvases can only be passed in on non mobile platforms func (canvas *Canvas) startGrab(canvases ...*Canvas) error { if gl_state.currentCanvas == canvas { return nil // already grabbing } if canvases != nil && len(canvases) > 0 { // Whether the new canvas list is different from the old one. // A more thorough check is done below. if maxRenderTargets < 4 { return fmt.Errorf("Multi-canvas rendering is not supported on this system.") } if int32(len(canvases)+1) > maxRenderTargets { return fmt.Errorf("This system can't simultaneously render to %v canvases.", len(canvases)+1) } for i := 0; i < len(canvases); i++ { if canvases[i].width != canvas.width || canvases[i].height != canvas.height { return fmt.Errorf("All canvases must have the same dimensions.") } } } // cleanup after previous Canvas if gl_state.currentCanvas != nil { canvas.systemViewport = gl_state.currentCanvas.systemViewport gl_state.currentCanvas.stopGrab(true) } else { canvas.systemViewport = GetViewport() } // indicate we are using this Canvas. gl_state.currentCanvas = canvas // bind the framebuffer object. gl.BindFramebuffer(gl.FRAMEBUFFER, canvas.fbo) SetViewport(0, 0, canvas.width, canvas.height) // Set up the projection matrix gl_state.projectionStack.Push() gl_state.projectionStack.Load(mgl32.Ortho(0.0, float32(screen_width), 0.0, float32(screen_height), -1, 1)) canvas.attacheExtra(canvases) canvas.attachedCanvases = canvases return nil }