def __init__(self, texture, *args, **kwargs): """A Framebuffer object, which when bound redirects draws to its texture. This is useful for deferred rendering.""" super(FBO, self).__init__(*args, **kwargs) self._old_viewport_size = (gl.GLint * 4)() self.texture = texture self.renderbuffer = tex.RenderBuffer( texture.width, texture.height) if not isinstance( texture, tex.DepthTexture) else None with self: #, self.texture: # TODO: Figure out whether texture should also be bound here. # Attach the textures to the FBO for texture in [self.texture, self.renderbuffer ] if self.renderbuffer else [self.texture]: texture.attach_to_fbo() # Set Draw and Read locations for the FBO (currently, just turn it off if not doing any color stuff) if isinstance(texture, tex.DepthTexture): gl.glDrawBuffer(gl.GL_NONE) # No color in this buffer gl.glReadBuffer(gl.GL_NONE) # check FBO status (warning appears for debugging) FBOstatus = gl.glCheckFramebufferStatusEXT(gl.GL_FRAMEBUFFER_EXT) if FBOstatus != gl.GL_FRAMEBUFFER_COMPLETE_EXT: raise BufferError( "GL_FRAMEBUFFER_COMPLETE failed, CANNOT use FBO.\n{0}\n". format(FBOstatus))
def __init__(self, texture, *args, **kwargs): """A Framebuffer object, which when bound redirects draws to its texture. This is useful for deferred rendering.""" super(FBO, self).__init__(*args, **kwargs) self.id = create_opengl_object(gl.glGenFramebuffersEXT) self._old_viewport = get_viewport() self.texture = texture self.renderbuffer = RenderBuffer( texture.width, texture.height) if not isinstance(texture, DepthTexture) else None with self: # Attach the textures to the FBO self.texture.attach_to_fbo() if self.renderbuffer: self.renderbuffer.attach_to_fbo() # Set Draw and Read locations for the FBO (currently, just turn it off if not doing any color stuff) if isinstance(texture, DepthTexture): gl.glDrawBuffer(gl.GL_NONE) # No color in this buffer gl.glReadBuffer(gl.GL_NONE) # check FBO status (warning appears for debugging) FBOstatus = gl.glCheckFramebufferStatusEXT(gl.GL_FRAMEBUFFER_EXT) if FBOstatus != gl.GL_FRAMEBUFFER_COMPLETE_EXT: raise BufferError( "GL_FRAMEBUFFER_COMPLETE failed, CANNOT use FBO.\n{0}\n". format(FBOstatus))
def _blit_buffer_direct(self, framebuffer, parent_framebuffer, width, height, parent_width, parent_height, transformation, **kwargs): # XXX: Use this instead of blit_buffer when we don't need # colorizing/opacity transformation.reset() gl.glViewport(0, 0, width, height) gl.glBindFramebufferEXT(gl.GL_READ_FRAMEBUFFER_EXT, framebuffer.framebuffer_id) gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0_EXT) gl.glBindFramebufferEXT(gl.GL_DRAW_FRAMEBUFFER_EXT, parent_framebuffer.framebuffer_id) gl.glBlitFramebufferEXT(0, 0, width, height, 0, 0, parent_width, parent_height, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) gl.glDisable(gl.GL_TEXTURE_2D)
def read_pixel(self, name: str, x: int, y: int, gl_type=gl.GL_FLOAT, gl_format=gl.GL_RGBA): """ This is probably inefficient, but a useful way to find e.g. the scene position under the mouse cursor. """ c_type = GLTYPE_TO_CTYPE[gl_type] texture = self.textures[name] position_value = (c_type * 4)() with self: gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0 + texture.unit) gl.glReadPixels(x, y, 1, 1, gl_format, gl_type, byref(position_value)) return list(position_value)
def read_buffer(self, format='rgb'): """Read back the recently rendered color data from the window's buffer. Returns ------- data : unit8 array, shape=(height, width, n_channels) RGB or RGBA color data. Details ------- Call to `.read_buffer()` should be preceded by `.render()` in order to read the latest color data. The dims of the returned color array correspond to the width and height of the gl color buffer used for rendering, and may not coincide with the dims of the original image. Typically, they correspond to the window dims scaled by some factor. """ if not self.isopen: raise RuntimeError('Cannot read color data from a closed viewer.') assert format in ('rgb', 'rgba') if format == 'rgb': format, n_channels = gl.GL_RGB, 3 else: format, n_channels = gl.GL_RGBA, 4 # ensure current gl context self.switch_to() # make sure the color data we read back is fresh # self.on_draw() # `.flip()` x2 may cause unnecessary vsync and flicker # allocate unit8 buffer for RGB data width, height = self.get_framebuffer_size() buf = (gl.GLubyte * (height * width * n_channels))(0) # read a block of pixels from the current display frame buffer gl.glReadBuffer(gl.GL_FRONT) # FRONT -- display, BACK -- drawing gl.glReadPixels(0, 0, width, height, format, gl.GL_UNSIGNED_BYTE, buf) # properly reshape and reorder the data flat = np.frombuffer(buf, dtype=np.uint8) return flat.reshape(height, width, n_channels)[::-1].copy()
def __init__(self, texture, *args, **kwargs): """A Framebuffer object, which when bound redirects draws to its texture. This is useful for deferred rendering.""" super(FBO, self).__init__(*args, **kwargs) self._old_viewport_size = (gl.GLint * 4)() self.texture = texture self.renderbuffer = tex.RenderBuffer(texture.width, texture.height) if not isinstance(texture, tex.DepthTexture) else None with self: #, self.texture: # TODO: Figure out whether texture should also be bound here. # Attach the textures to the FBO for texture in [self.texture, self.renderbuffer] if self.renderbuffer else [self.texture]: texture.attach_to_fbo() # Set Draw and Read locations for the FBO (currently, just turn it off if not doing any color stuff) if isinstance(texture, tex.DepthTexture): gl.glDrawBuffer(gl.GL_NONE) # No color in this buffer gl.glReadBuffer(gl.GL_NONE) # check FBO status (warning appears for debugging) FBOstatus = gl.glCheckFramebufferStatusEXT(gl.GL_FRAMEBUFFER_EXT) if FBOstatus != gl.GL_FRAMEBUFFER_COMPLETE_EXT: raise BufferError("GL_FRAMEBUFFER_COMPLETE failed, CANNOT use FBO.\n{0}\n".format(FBOstatus))
p['offset'] = [-1.0, 0.0] p['width_ratio'] = float(WIDTH)/HEIGHT p['zoom'] = 2.0 # Draw on the framebuffer draw_canvas() p.disable() # Copy the data from the graphics card to system memory import numpy as np import ctypes arr = np.empty((HEIGHT, WIDTH, 3), dtype=np.float32) gl.glFinish() gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0_EXT) gl.glReadPixels(0, 0, WIDTH, HEIGHT, gl.GL_RGB, gl.GL_FLOAT, arr.ctypes.data) # Display using matplotlib (TODO: use opengl to display) import matplotlib.pyplot as plt plt.imshow(arr) plt.show() fbo.unbind() gl.glPopAttrib()