def gl_init(self): drawable = self.gl_begin() w, h = self.size debug("GL Pixmap backing size: %d x %d, drawable=%s", w, h, drawable) if not drawable: return None if not self.gl_setup: # Ask GL to send us all debug messages if GL_DEBUG_OUTPUT and gl_debug_callback and glInitDebugKHR() == True: glEnable(GL_DEBUG_OUTPUT) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS) glDebugMessageCallback(gl_debug_callback, None) glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, None, GL_TRUE) # Initialize string_marker GL debugging extension if available if glInitStringMarkerGREMEDY and glInitStringMarkerGREMEDY() == True: log.info("Extension GL_GREMEDY_string_marker available. Will output detailed information about each frame.") else: # General case - running without debugger, extension not available glStringMarkerGREMEDY = None # Initialize frame_terminator GL debugging extension if available if glInitFrameTerminatorGREMEDY and glInitFrameTerminatorGREMEDY() == True: glFrameTerminatorGREMEDY = None self.gl_marker("Initializing GL context for window size %d x %d" % (w, h)) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) #TODO glEnableClientState(GL_VERTEX_ARRAY) #TODO glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear to white glClearColor(1.0, 1.0, 1.0, 1.0) # Default state is good for YUV painting: # - fragment program enabled # - render to offscreen FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) if self.textures is None: self.textures = glGenTextures(5) debug("textures for wid=%s of size %s : %s", self.wid, self.size, self.textures) if self.offscreen_fbo is None: self.offscreen_fbo = glGenFramebuffers(1) # Define empty FBO texture and set rendering to FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) self.gl_setup = True return drawable
def gl_init(self): #must be called within a context! #performs init if needed if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: w, h = self.size self.gl_marker("Initializing GL context for window size %d x %d", w, h) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Mesa docs claim: this hint can improve the speed of texturing #when perspective-correct texture coordinate interpolation isn't needed, #such as when using a glOrtho() projection: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() # Define empty FBO texture and set rendering to FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) self.gl_setup = True
def gl_init(self): drawable = self.gl_begin() w, h = self.size log("%s.gl_init() GL Pixmap backing size: %d x %d, drawable=%s", self, w, h, drawable) if not drawable: return None if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: self.gl_marker("Initializing GL context for window size %d x %d" % (w, h)) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() # Define empty FBO texture and set rendering to FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) self.gl_setup = True return drawable
def present_fbo(self, drawable): self.gl_marker("Presenting FBO on screen for drawable %s" % drawable) assert drawable # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._has_alpha: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._has_alpha: # support alpha channel if present: glEnable(GL_BLEND) glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO) w, h = self.size glBegin(GL_QUADS) glTexCoord2i(0, h) glVertex2i(0, 0) glTexCoord2i(0, 0) glVertex2i(0, h) glTexCoord2i(w, 0) glVertex2i(w, h) glTexCoord2i(w, h) glVertex2i(w, 0) glEnd() # Show the backbuffer on screen if drawable.is_double_buffered(): debug("%s.present_fbo() swapping buffers now", self) drawable.swap_buffers() # Clear the new backbuffer to illustrate that its contents are undefined glClear(GL_COLOR_BUFFER_BIT) else: glFlush() if self._has_alpha: glDisable(GL_BLEND) self.gl_frame_terminator() self.unset_rgb_paint_state() glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) debug("%s.present_fbo() done", self)
def present_fbo(self): drawable = self.gl_init() debug("present_fbo() drawable=%s", drawable) self.gl_marker("Presenting FBO on screen") if not drawable: return # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) # Draw FBO texture on screen self.set_rgb24_paint_state() glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) w, h = self.size glBegin(GL_QUADS) glTexCoord2i(0, h) glVertex2i(0, 0) glTexCoord2i(0, 0) glVertex2i(0, h) glTexCoord2i(w, 0) glVertex2i(w, h) glTexCoord2i(w, h) glVertex2i(w, 0) glEnd() # Show the backbuffer on screen if drawable.is_double_buffered(): debug("SWAPPING BUFFERS NOW") drawable.swap_buffers() # Clear the new backbuffer to illustrate that its contents are undefined glClear(GL_COLOR_BUFFER_BIT) else: glFlush() self.gl_frame_terminator() self.unset_rgb24_paint_state() glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) drawable.gl_end()
def do_present_fbo(self): bw, bh = self.size ww, wh = self.render_size rect_count = len(self.pending_fbo_paint) if self.is_double_buffered() or bw!=ww or bh!=wh: #refresh the whole window: rectangles = ((0, 0, bw, bh), ) else: #paint just the rectangles we have accumulated: rectangles = self.pending_fbo_paint self.pending_fbo_paint = [] log("do_present_fbo: painting %s", rectangles) if SAVE_BUFFERS: self.save_FBO() self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) left, top, right, bottom = self.offsets #viewport for clearing the whole window: glViewport(0, 0, left+ww+right, top+wh+bottom) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # black, no alpha: glClearColor(0.0, 0.0, 0.0, 1.0) if left or top or right or bottom: glClear(GL_COLOR_BUFFER_BIT) #from now on, take the offsets into account: glViewport(left, top, ww, wh) target = GL_TEXTURE_RECTANGLE_ARB if ww!=bw or wh!=bh: glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR) # Draw FBO texture on screen glEnable(target) #redundant - done in rgb paint state glBindTexture(target, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) glBegin(GL_QUADS) for x,y,w,h in rectangles: #note how we invert coordinates.. tx1, ty1, tx2, ty2 = x, bh-y, x+w, bh-y-h vx1, vy1, vx2, vy2 = x, y, x+w, y+h glTexCoord2i(tx1, ty1) glVertex2i(vx1, vy1) #top-left of window viewport glTexCoord2i(tx1, ty2) glVertex2i(vx1, vy2) #bottom-left of window viewport glTexCoord2i(tx2, ty2) glVertex2i(vx2, vy2) #bottom-right of window viewport glTexCoord2i(tx2, ty1) glVertex2i(vx2, vy1) #top-right of window viewport glEnd() glBindTexture(target, 0) glDisable(target) if self.pointer_overlay: self.draw_pointer() if self.paint_spinner: #add spinner: self.draw_spinner() if self.border and self.border.shown: self.draw_border() # Show the backbuffer on screen glFlush() self.gl_show(rect_count) self.gl_frame_terminator() #restore pbo viewport glViewport(0, 0, bw, bh) glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST) log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.do_present_fbo() done", self)
def gl_init(self): drawable = self.gl_begin() w, h = self.size debug("%s.gl_init() GL Pixmap backing size: %d x %d, drawable=%s", self, w, h, drawable) if not drawable: return None if not self.gl_setup: #ensure python knows which scope we're talking about: global glInitStringMarkerGREMEDY, glStringMarkerGREMEDY global glInitFrameTerminatorGREMEDY, glFrameTerminatorGREMEDY # Ask GL to send us all debug messages if GL_DEBUG_OUTPUT and gl_debug_callback and glInitDebugKHR() == True: glEnable(GL_DEBUG_OUTPUT) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS) glDebugMessageCallback(gl_debug_callback, None) glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, None, GL_TRUE) # Initialize string_marker GL debugging extension if available if glInitStringMarkerGREMEDY and glInitStringMarkerGREMEDY() == True: log.info("Extension GL_GREMEDY_string_marker available. Will output detailed information about each frame.") else: # General case - running without debugger, extension not available glStringMarkerGREMEDY = None #don't bother trying again for another window: glInitStringMarkerGREMEDY = None # Initialize frame_terminator GL debugging extension if available if glInitFrameTerminatorGREMEDY and glInitFrameTerminatorGREMEDY() == True: log.info("Enabling GL frame terminator debugging.") else: glFrameTerminatorGREMEDY = None #don't bother trying again for another window: glInitFrameTerminatorGREMEDY = None self.gl_marker("Initializing GL context for window size %d x %d" % (w, h)) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) #TODO glEnableClientState(GL_VERTEX_ARRAY) #TODO glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear to white glClearColor(1.0, 1.0, 1.0, 1.0) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) if self.textures is None: self.textures = glGenTextures(5) debug("%s.gl_init() textures of size %s : %s", self, self.size, self.textures) if self.offscreen_fbo is None: self.offscreen_fbo = glGenFramebuffers(1) # Define empty FBO texture and set rendering to FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Create and assign fragment programs if not self.shaders: self.shaders = [ 1, 2 ] glGenProgramsARB(2, self.shaders) for progid, progstr in ((0, YUV2RGB_shader), (1, RGBP2RGB_shader)): glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[progid]) glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, len(progstr), progstr) err = glGetString(GL_PROGRAM_ERROR_STRING_ARB) if err: #FIXME: maybe we should do something else here? log.error(err) # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[0]) self.gl_setup = True return drawable
def gl_init(self): #must be called within a context! #performs init if needed if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: w, h = self.size self.gl_marker("Initializing GL context for window size %s, backing size %s", self.render_size, self.size) # Initialize viewport and matrices for 2D rendering x, _, _, y = self.offsets glViewport(x, y, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Mesa docs claim: this hint can improve the speed of texturing #when perspective-correct texture coordinate interpolation isn't needed, #such as when using a glOrtho() projection: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) glDisable(GL_SCISSOR_TEST) glDisable(GL_LIGHTING) glDisable(GL_DITHER) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() #upload pixel buffer full of zeroes: empty_buf = b"\0"*(w*h*4) pixel_data = self.pixels_for_upload(empty_buf)[1] # Define empty tmp FBO target = GL_TEXTURE_RECTANGLE_ARB glBindTexture(target, self.textures[TEX_TMP_FBO]) set_texture_level(target) glTexImage2D(target, 0, self.internal_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, pixel_data) glBindFramebuffer(GL_FRAMEBUFFER, self.tmp_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_TMP_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Define empty FBO texture and set rendering to FBO glBindTexture(target, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): set_texture_level(target) glTexImage2D(target, 0, self.internal_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, pixel_data) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) glBindTexture(target, 0) # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) self.gl_setup = True
def do_scroll_paints(self, scrolls, flush=0, callbacks=[]): log("do_scroll_paints%s", (scrolls, flush)) context = self.gl_context() if not context: log("%s.do_scroll_paints(..) no context!", self) fire_paint_callbacks(callbacks, False, "no opengl context") return def fail(msg): log.error("Error: %s", msg) fire_paint_callbacks(callbacks, False, msg) with context: bw, bh = self.size #paste from offscreen to tmp with delta offset: glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) target = GL_TEXTURE_RECTANGLE_ARB glEnable(target) glBindTexture(target, self.textures[TEX_FBO]) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0) glReadBuffer(GL_COLOR_ATTACHMENT0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.tmp_fbo) glBindTexture(target, self.textures[TEX_TMP_FBO]) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, target, self.textures[TEX_TMP_FBO], 0) glDrawBuffer(GL_COLOR_ATTACHMENT1) #copy current fbo: glBlitFramebuffer(0, 0, bw, bh, 0, 0, bw, bh, GL_COLOR_BUFFER_BIT, GL_NEAREST) for x,y,w,h,xdelta,ydelta in scrolls: if abs(xdelta)>=bw: fail("invalid xdelta value: %i, backing width is %i" % (xdelta, bw)) continue if abs(ydelta)>=bh: fail("invalid ydelta value: %i, backing height is %i" % (ydelta, bh)) continue if ydelta==0 and xdelta==0: fail("scroll has no delta!") continue if w<=0 or h<=0: fail("invalid scroll area size: %ix%i" % (w, h)) continue #these should be errors, #but desktop-scaling can cause a mismatch between the backing size #and the real window size server-side.. so we clamp the dimensions instead if x+w>bw: w = bw-x if y+h>bh: h = bh-y if x+w+xdelta>bw: w = bw-x-xdelta if w<=0: continue #nothing left! if y+h+ydelta>bh: h = bh-y-ydelta if h<=0: continue #nothing left! if x+xdelta<0: fail("horizontal scroll by %i: rectangle %s overflows the backing buffer size %s" % (xdelta, (x, y, w, h), self.size)) continue if y+ydelta<0: fail("vertical scroll by %i: rectangle %s overflows the backing buffer size %s" % (ydelta, (x, y, w, h), self.size)) continue #opengl buffer is upside down, so we must invert Y coordinates: bh-(..) glBlitFramebuffer(x, bh-y, x+w, bh-(y+h), x+xdelta, bh-(y+ydelta), x+w+xdelta, bh-(y+h+ydelta), GL_COLOR_BUFFER_BIT, GL_NEAREST) self.paint_box("scroll", True, x+xdelta, y+ydelta, x+w+xdelta, y+h+ydelta) glFlush() #now swap references to tmp and offscreen so tmp becomes the new offscreen: tmp = self.offscreen_fbo self.offscreen_fbo = self.tmp_fbo self.tmp_fbo = tmp tmp = self.textures[TEX_FBO] self.textures[TEX_FBO] = self.textures[TEX_TMP_FBO] self.textures[TEX_TMP_FBO] = tmp #restore normal paint state: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0) glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glBindTexture(target, 0) glDisable(target) fire_paint_callbacks(callbacks, True) self.present_fbo(0, 0, bw, bh, flush)
def present_fbo(self, encoding, is_delta, x, y, w, h): if not self.paint_screen: return self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() ww, wh = self.size if self.glconfig.is_double_buffered(): #refresh the whole window: x, y = 0, 0 w, h = ww, wh glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) glBegin(GL_QUADS) #note how we invert coordinates.. glTexCoord2i(x, wh-y) glVertex2i(x, y) #top-left of window viewport glTexCoord2i(x, wh-y-h) glVertex2i(x, y+h) #bottom-left of window viewport glTexCoord2i(x+w, wh-y-h) glVertex2i(x+w, y+h) #bottom-right of window viewport glTexCoord2i(x+w, wh-y) glVertex2i(x+w, y) #top-right of window viewport glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) #show region being painted: if OPENGL_PAINT_BOX: glLineWidth(1) if is_delta: glLineStipple(1, 0xf0f0) glEnable(GL_LINE_STIPPLE) glBegin(GL_LINE_LOOP) color = BOX_COLORS.get(encoding, _DEFAULT_BOX_COLOR) glColor4f(*color) for px,py in ((x, y), (x+w, y), (x+w, y+h), (x, y+h)): glVertex2i(px, py) glEnd() if is_delta: glDisable(GL_LINE_STIPPLE) if self.paint_spinner: #add spinner: dim = min(ww/3.0, wh/3.0) t = time.time() count = int(t*4.0) bx = ww//2 by = wh//2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count%8][i] glColor4f(c, c, c, 1) mi1 = math.pi*i/4-math.pi/16 mi2 = math.pi*i/4+math.pi/16 glVertex2i(int(bx+math.sin(mi1)*10), int(by+math.cos(mi1)*10)) glVertex2i(int(bx+math.sin(mi1)*dim), int(by+math.cos(mi1)*dim)) glVertex2i(int(bx+math.sin(mi2)*dim), int(by+math.cos(mi2)*dim)) glVertex2i(int(bx+math.sin(mi2)*10), int(by+math.cos(mi2)*10)) glEnd() #if desired, paint window border if self.border and self.border.shown: #double size since half the line will be off-screen glLineWidth(self.border.size*2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px,py in ((0, 0), (ww, 0), (ww, wh), (0, wh)): glVertex2i(px, py) glEnd() # Show the backbuffer on screen self.gl_show() self.gl_frame_terminator() self.unset_rgb_paint_state() log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.present_fbo() done", self)
def present_fbo(self, drawable): if not self.paint_screen: return self.gl_marker("Presenting FBO on screen for drawable %s" % drawable) assert drawable # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._has_alpha: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() w, h = self.size glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._has_alpha and bool(glEnablei): # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glBegin(GL_QUADS) glTexCoord2i(0, h) glVertex2i(0, 0) glTexCoord2i(0, 0) glVertex2i(0, h) glTexCoord2i(w, 0) glVertex2i(w, h) glTexCoord2i(w, h) glVertex2i(w, 0) glEnd() #if desired, paint window border if self.border and self.border.shown: glDisable(GL_TEXTURE_RECTANGLE_ARB) #double size since half the line will be off-screen glLineWidth(self.border.size * 2) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) glBegin(GL_LINE_LOOP) for x, y in ((0, 0), (w, 0), (w, h), (0, h)): glVertex2i(x, y) glEnd() #reset color to default glColor4f(1.0, 1.0, 1.0, 1.0) # Show the backbuffer on screen if drawable.is_double_buffered(): log("%s.present_fbo() swapping buffers now", self) drawable.swap_buffers() # Clear the new backbuffer to illustrate that its contents are undefined glClear(GL_COLOR_BUFFER_BIT) else: glFlush() self.gl_frame_terminator() self.unset_rgb_paint_state() glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.present_fbo() done", self)
def do_present_fbo(self): self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() bw, bh = self.size ww, wh = self.render_size if self.glconfig.is_double_buffered() or bw != ww or bh != wh: #refresh the whole window: rectangles = ((0, 0, bw, bh), ) else: #paint just the rectangles we have accumulated: rectangles = self.pending_fbo_paint self.pending_fbo_paint = [] log("do_present_fbo: painting %s", rectangles) glEnable(GL_TEXTURE_RECTANGLE_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) #viewport for painting to window: glViewport(0, 0, ww, wh) if ww != bw or wh != bh: glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glBegin(GL_QUADS) for x, y, w, h in rectangles: #note how we invert coordinates.. tx1, ty1, tx2, ty2 = x, bh - y, x + w, bh - y - h vx1, vy1, vx2, vy2 = x, y, x + w, y + h glTexCoord2i(tx1, ty1) glVertex2i(vx1, vy1) #top-left of window viewport glTexCoord2i(tx1, ty2) glVertex2i(vx1, vy2) #bottom-left of window viewport glTexCoord2i(tx2, ty2) glVertex2i(vx2, vy2) #bottom-right of window viewport glTexCoord2i(tx2, ty1) glVertex2i(vx2, vy1) #top-right of window viewport glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) if self.paint_spinner: #add spinner: dim = min(bw / 3.0, bh / 3.0) t = time.time() count = int(t * 4.0) bx = bw // 2 by = bh // 2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count % 8][i] glColor4f(c, c, c, 1) mi1 = math.pi * i / 4 - math.pi / 16 mi2 = math.pi * i / 4 + math.pi / 16 glVertex2i(int(bx + math.sin(mi1) * 10), int(by + math.cos(mi1) * 10)) glVertex2i(int(bx + math.sin(mi1) * dim), int(by + math.cos(mi1) * dim)) glVertex2i(int(bx + math.sin(mi2) * dim), int(by + math.cos(mi2) * dim)) glVertex2i(int(bx + math.sin(mi2) * 10), int(by + math.cos(mi2) * 10)) glEnd() #if desired, paint window border if self.border and self.border.shown: #double size since half the line will be off-screen glLineWidth(self.border.size * 2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px, py in ((0, 0), (bw, 0), (bw, bh), (0, bh)): glVertex2i(px, py) glEnd() # Show the backbuffer on screen self.gl_show() self.gl_frame_terminator() #restore pbo viewport glViewport(0, 0, bw, bh) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST) self.unset_rgb_paint_state() log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.do_present_fbo() done", self)
def gl_init(self): drawable = self.gl_begin() w, h = self.size debug("GL Pixmap backing size: %d x %d, drawable=%s", w, h, drawable) if not drawable: return None if not self.gl_setup: # Ask GL to send us all debug messages if GL_DEBUG_OUTPUT and gl_debug_callback and glInitDebugKHR( ) == True: glEnable(GL_DEBUG_OUTPUT) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS) glDebugMessageCallback(gl_debug_callback, None) glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, None, GL_TRUE) # Initialize string_marker GL debugging extension if available if glInitStringMarkerGREMEDY and glInitStringMarkerGREMEDY( ) == True: log.info( "Extension GL_GREMEDY_string_marker available. Will output detailed information about each frame." ) else: # General case - running without debugger, extension not available glStringMarkerGREMEDY = None # Initialize frame_terminator GL debugging extension if available if glInitFrameTerminatorGREMEDY and glInitFrameTerminatorGREMEDY( ) == True: glFrameTerminatorGREMEDY = None self.gl_marker("Initializing GL context for window size %d x %d" % (w, h)) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) #TODO glEnableClientState(GL_VERTEX_ARRAY) #TODO glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear to white glClearColor(1.0, 1.0, 1.0, 1.0) # Default state is good for YUV painting: # - fragment program enabled # - render to offscreen FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) if self.textures is None: self.textures = glGenTextures(5) debug("textures for wid=%s of size %s : %s", self.wid, self.size, self.textures) if self.offscreen_fbo is None: self.offscreen_fbo = glGenFramebuffers(1) # Define empty FBO texture and set rendering to FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) self.gl_setup = True return drawable
def present_fbo(self, drawable): if not self.paint_screen: return self.gl_marker("Presenting FBO on screen for drawable %s" % drawable) assert drawable # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() w, h = self.size glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) glBegin(GL_QUADS) glTexCoord2i(0, h) glVertex2i(0, 0) glTexCoord2i(0, 0) glVertex2i(0, h) glTexCoord2i(w, 0) glVertex2i(w, h) glTexCoord2i(w, h) glVertex2i(w, 0) glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) if self.paint_spinner: #add spinner: dim = min(w / 3.0, h / 3.0) t = time.time() count = int(t * 4.0) bx = w // 2 by = h // 2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count % 8][i] glColor4f(c, c, c, 1) mi1 = math.pi * i / 4 - math.pi / 16 mi2 = math.pi * i / 4 + math.pi / 16 glVertex2i(int(bx + math.sin(mi1) * 10), int(by + math.cos(mi1) * 10)) glVertex2i(int(bx + math.sin(mi1) * dim), int(by + math.cos(mi1) * dim)) glVertex2i(int(bx + math.sin(mi2) * dim), int(by + math.cos(mi2) * dim)) glVertex2i(int(bx + math.sin(mi2) * 10), int(by + math.cos(mi2) * 10)) glEnd() #if desired, paint window border if self.border and self.border.shown: glDisable(GL_TEXTURE_RECTANGLE_ARB) #double size since half the line will be off-screen glLineWidth(self.border.size * 2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px, py in ((0, 0), (w, 0), (w, h), (0, h)): glVertex2i(px, py) glEnd() #reset color to default glColor4f(1.0, 1.0, 1.0, 1.0) # Show the backbuffer on screen if drawable.is_double_buffered(): log("%s.present_fbo() swapping buffers now", self) drawable.swap_buffers() # Clear the new backbuffer to illustrate that its contents are undefined glClear(GL_COLOR_BUFFER_BIT) else: glFlush() self.gl_frame_terminator() self.unset_rgb_paint_state() glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.present_fbo() done", self)
def gl_init(self): #must be called within a context! #performs init if needed if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: mt = get_max_texture_size() rw, rh = self.render_size w, h = self.size if w>mt or h>mt: raise Exception("invalid texture dimensions %ix%i, maximum is %i" % (w, h, mt)) self.gl_marker("Initializing GL context for window size %s, backing size %s, max texture size=%i", self.render_size, self.size, mt) # Initialize viewport and matrices for 2D rendering x, _, _, y = self.offsets glViewport(x, y, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Mesa docs claim: this hint can improve the speed of texturing #when perspective-correct texture coordinate interpolation isn't needed, #such as when using a glOrtho() projection: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) glDisable(GL_SCISSOR_TEST) glDisable(GL_LIGHTING) glDisable(GL_DITHER) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() mag_filter = GL_NEAREST if float(rw)/w!=rw//w or float(rh)/h!=rh//h: #non integer scaling, use linear magnification filter: mag_filter = GL_LINEAR log("initializing FBOs") # Define empty tmp FBO target = GL_TEXTURE_RECTANGLE_ARB glBindTexture(target, self.textures[TEX_TMP_FBO]) glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter) glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexImage2D(target, 0, self.internal_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.tmp_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_TMP_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Define empty FBO texture and set rendering to FBO glBindTexture(target, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter) glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexImage2D(target, 0, self.internal_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) glBindTexture(target, 0) # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) self.gl_setup = True log("gl_init() done")
def gl_init(self): drawable = self.gl_begin() w, h = self.size debug("%s.gl_init() GL Pixmap backing size: %d x %d, drawable=%s", self, w, h, drawable) if not drawable: return None if not self.gl_setup: #ensure python knows which scope we're talking about: global glInitStringMarkerGREMEDY, glStringMarkerGREMEDY global glInitFrameTerminatorGREMEDY, glFrameTerminatorGREMEDY # Ask GL to send us all debug messages if GL_DEBUG_OUTPUT and gl_debug_callback and glInitDebugKHR( ) == True: glEnable(GL_DEBUG_OUTPUT) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS) glDebugMessageCallback(gl_debug_callback, None) glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, None, GL_TRUE) # Initialize string_marker GL debugging extension if available if glInitStringMarkerGREMEDY and glInitStringMarkerGREMEDY( ) == True: log.info( "Extension GL_GREMEDY_string_marker available. Will output detailed information about each frame." ) else: # General case - running without debugger, extension not available glStringMarkerGREMEDY = None #don't bother trying again for another window: glInitStringMarkerGREMEDY = None # Initialize frame_terminator GL debugging extension if available if glInitFrameTerminatorGREMEDY and glInitFrameTerminatorGREMEDY( ) == True: log.info("Enabling GL frame terminator debugging.") else: glFrameTerminatorGREMEDY = None #don't bother trying again for another window: glInitFrameTerminatorGREMEDY = None self.gl_marker("Initializing GL context for window size %d x %d" % (w, h)) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) #TODO glEnableClientState(GL_VERTEX_ARRAY) #TODO glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear to white glClearColor(1.0, 1.0, 1.0, 1.0) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) if self.textures is None: self.textures = glGenTextures(5) debug("%s.gl_init() textures of size %s : %s", self, self.size, self.textures) if self.offscreen_fbo is None: self.offscreen_fbo = glGenFramebuffers(1) # Define empty FBO texture and set rendering to FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0) glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Create and assign fragment programs if not self.shaders: self.shaders = [1, 2] glGenProgramsARB(2, self.shaders) for progid, progstr in ((0, YUV2RGB_shader), (1, RGBP2RGB_shader)): glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[progid]) glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, len(progstr), progstr) err = glGetString(GL_PROGRAM_ERROR_STRING_ARB) if err: #FIXME: maybe we should do something else here? log.error(err) # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[0]) self.gl_setup = True return drawable
def do_present_fbo(self): bw, bh = self.size ww, wh = self.render_size self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() rect_count = len(self.pending_fbo_paint) if self.glconfig.is_double_buffered() or bw!=ww or bh!=wh: #refresh the whole window: rectangles = ((0, 0, bw, bh), ) else: #paint just the rectangles we have accumulated: rectangles = self.pending_fbo_paint self.pending_fbo_paint = [] log("do_present_fbo: painting %s", rectangles) glEnable(GL_TEXTURE_RECTANGLE_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) if SAVE_BUFFERS: glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glReadBuffer(GL_COLOR_ATTACHMENT0) glViewport(0, 0, bw, bh) from OpenGL.GL import glGetTexImage size = bw*bh*4 import numpy data = numpy.empty(size) img_data = glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data) from PIL import Image, ImageOps img = Image.frombuffer("RGBA", (bw, bh), img_data, "raw", "BGRA", bw*4) img = ImageOps.flip(img) kwargs = {} if SAVE_BUFFERS=="jpeg": kwargs = { "quality" : 0, "optimize" : False, } t = time.time() tstr = time.strftime("%H-%M-%S", time.localtime(t)) filename = "./W%i-FBO-%s.%03i.%s" % (self.wid, tstr, (t*1000)%1000, SAVE_BUFFERS) log("do_present_fbo: saving %4ix%-4i pixels, %7i bytes to %s", bw, bh, size, filename) img.save(filename, SAVE_BUFFERS, **kwargs) glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) #viewport for painting to window: glViewport(0, 0, ww, wh) if ww!=bw or wh!=bh: glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glBegin(GL_QUADS) for x,y,w,h in rectangles: #note how we invert coordinates.. tx1, ty1, tx2, ty2 = x, bh-y, x+w, bh-y-h vx1, vy1, vx2, vy2 = x, y, x+w, y+h glTexCoord2i(tx1, ty1) glVertex2i(vx1, vy1) #top-left of window viewport glTexCoord2i(tx1, ty2) glVertex2i(vx1, vy2) #bottom-left of window viewport glTexCoord2i(tx2, ty2) glVertex2i(vx2, vy2) #bottom-right of window viewport glTexCoord2i(tx2, ty1) glVertex2i(vx2, vy1) #top-right of window viewport glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) if self.paint_spinner: #add spinner: dim = min(bw/3.0, bh/3.0) t = time.time() count = int(t*4.0) bx = bw//2 by = bh//2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count%8][i] glColor4f(c, c, c, 1) mi1 = math.pi*i/4-math.pi/16 mi2 = math.pi*i/4+math.pi/16 glVertex2i(int(bx+math.sin(mi1)*10), int(by+math.cos(mi1)*10)) glVertex2i(int(bx+math.sin(mi1)*dim), int(by+math.cos(mi1)*dim)) glVertex2i(int(bx+math.sin(mi2)*dim), int(by+math.cos(mi2)*dim)) glVertex2i(int(bx+math.sin(mi2)*10), int(by+math.cos(mi2)*10)) glEnd() #if desired, paint window border if self.border and self.border.shown: #double size since half the line will be off-screen glLineWidth(self.border.size*2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px,py in ((0, 0), (bw, 0), (bw, bh), (0, bh)): glVertex2i(px, py) glEnd() if self.pointer_overlay: x, y, _, _, size, start_time = self.pointer_overlay elapsed = time.time()-start_time if elapsed<6: alpha = max(0, (5.0-elapsed)/5.0) glLineWidth(1) glBegin(GL_LINES) glColor4f(0, 0, 0, alpha) glVertex2i(x-size, y) glVertex2i(x+size, y) glVertex2i(x, y-size) glVertex2i(x, y+size) glEnd() else: self.pointer_overlay = None # Show the backbuffer on screen self.gl_show(rect_count) self.gl_frame_terminator() #restore pbo viewport glViewport(0, 0, bw, bh) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST) self.unset_rgb_paint_state() log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.do_present_fbo() done", self)
def do_scroll_paints(self, scrolls, flush=0, callbacks=[]): log("do_scroll_paints%s", (scrolls, flush)) context = self.gl_context() if not context: log.warn("Warning: cannot paint scroll, no OpenGL context!") return def fail(msg): log.error("Error: %s", msg) fire_paint_callbacks(callbacks, False, msg) with context: bw, bh = self.size self.set_rgb_paint_state() #paste from offscreen to tmp with delta offset: glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glReadBuffer(GL_COLOR_ATTACHMENT0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.tmp_fbo) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO]) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO], 0) glDrawBuffer(GL_COLOR_ATTACHMENT1) #copy current fbo: glBlitFramebuffer(0, 0, bw, bh, 0, 0, bw, bh, GL_COLOR_BUFFER_BIT, GL_NEAREST) for x,y,w,h,xdelta,ydelta in scrolls: if abs(xdelta)>=bw: fail("invalid xdelta value: %i" % xdelta) continue if abs(ydelta)>=bh: fail("invalid ydelta value: %i" % ydelta) continue if ydelta==0 and xdelta==0: fail("scroll has no delta!") continue if w<=0 or h<=0: fail("invalid scroll area size: %ix%i" % (w, h)) continue #these should be errors, #but desktop-scaling can cause a mismatch between the backing size #and the real window size server-side.. so we clamp the dimensions instead if x+w>bw: w = bw-x if y+h>bh: h = bh-y if x+w+xdelta>bw: w = bw-x-xdelta if w<=0: continue #nothing left! if y+h+ydelta>bh: h = bh-y-ydelta if h<=0: continue #nothing left! if x+xdelta<0: fail("horizontal scroll by %i: rectangle %s overflows the backing buffer size %s" % (xdelta, (x, y, w, h), self.size)) continue if y+ydelta<0: fail("vertical scroll by %i: rectangle %s overflows the backing buffer size %s" % (ydelta, (x, y, w, h), self.size)) continue #opengl buffer is upside down, so we must invert Y coordinates: bh-(..) glBlitFramebuffer(x, bh-y, x+w, bh-(y+h), x+xdelta, bh-(y+ydelta), x+w+xdelta, bh-(y+h+ydelta), GL_COLOR_BUFFER_BIT, GL_NEAREST) glFlush() #now swap references to tmp and offscreen so tmp becomes the new offscreen: tmp = self.offscreen_fbo self.offscreen_fbo = self.tmp_fbo self.tmp_fbo = tmp tmp = self.textures[TEX_FBO] self.textures[TEX_FBO] = self.textures[TEX_TMP_FBO] self.textures[TEX_TMP_FBO] = tmp #restore normal paint state: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) self.unset_rgb_paint_state() self.paint_box("scroll", True, x+xdelta, y+ydelta, x+w+xdelta, y+h+ydelta) self.present_fbo(0, 0, bw, bh, flush) fire_paint_callbacks(callbacks, True)
def gl_init(self): #must be called within a context! #performs init if needed if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: w, h = self.size self.gl_marker("Initializing GL context for window size %s, backing size %s", self.render_size, self.size) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Mesa docs claim: this hint can improve the speed of texturing #when perspective-correct texture coordinate interpolation isn't needed, #such as when using a glOrtho() projection: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) glDisable(GL_SCISSOR_TEST) glDisable(GL_LIGHTING) glDisable(GL_DITHER) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() def clear_fbo(): try: glClear(GL_COLOR_BUFFER_BIT) except Exception as e: log("glClear error", exc_info=True) log.warn("Warning: failed to clear FBO") log.warn(" %r", e) if getattr(e, "err", None)==1286: raise Exception("OpenGL error '%r' likely caused by buggy drivers" % e) # Define empty tmp FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO]) set_texture_level() glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.tmp_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO], 0) clear_fbo() # Define empty FBO texture and set rendering to FBO glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): set_texture_level() glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) clear_fbo() # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) glEnable(GL_FRAGMENT_PROGRAM_ARB) self.gl_setup = True
def present_fbo(self, drawable): if not self.paint_screen: return self.gl_marker("Presenting FBO on screen for drawable %s" % drawable) assert drawable # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() w, h = self.size glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glBegin(GL_QUADS) glTexCoord2i(0, h) glVertex2i(0, 0) glTexCoord2i(0, 0) glVertex2i(0, h) glTexCoord2i(w, 0) glVertex2i(w, h) glTexCoord2i(w, h) glVertex2i(w, 0) glEnd() #if desired, paint window border if self.border and self.border.shown: glDisable(GL_TEXTURE_RECTANGLE_ARB) #double size since half the line will be off-screen glLineWidth(self.border.size*2) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) glBegin(GL_LINE_LOOP) for x,y in ((0, 0), (w, 0), (w, h), (0, h)): glVertex2i(x, y) glEnd() #reset color to default glColor4f(1.0, 1.0, 1.0, 1.0) # Show the backbuffer on screen if drawable.is_double_buffered(): log("%s.present_fbo() swapping buffers now", self) drawable.swap_buffers() # Clear the new backbuffer to illustrate that its contents are undefined glClear(GL_COLOR_BUFFER_BIT) else: glFlush() self.gl_frame_terminator() self.unset_rgb_paint_state() glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.present_fbo() done", self)
def gl_init(self): #must be called within a context! #performs init if needed if not self.debug_setup: self.debug_setup = True self.gl_init_debug() if not self.gl_setup: w, h = self.size self.gl_marker( "Initializing GL context for window size %s, backing size %s", self.render_size, self.size) # Initialize viewport and matrices for 2D rendering glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, w, h, 0.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) # Mesa docs claim: this hint can improve the speed of texturing #when perspective-correct texture coordinate interpolation isn't needed, #such as when using a glOrtho() projection: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST) # Could be more optimal to use vertex arrays: # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_TEXTURE_COORD_ARRAY) # Clear background to transparent black glClearColor(0.0, 0.0, 0.0, 0.0) # we don't use the depth (2D only): glDisable(GL_DEPTH_TEST) glDisable(GL_SCISSOR_TEST) glDisable(GL_LIGHTING) glDisable(GL_DITHER) # only do alpha blending in present_fbo: glDisable(GL_BLEND) # Default state is good for YUV painting: # - fragment program enabled # - YUV fragment program bound # - render to offscreen FBO if self.textures is None: self.gl_init_textures() # Define empty FBO texture and set rendering to FBO glEnable(GL_FRAGMENT_PROGRAM_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) # nvidia needs this even though we don't use mipmaps (repeated through this file): glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_BASE_LEVEL, 0) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAX_LEVEL, 0) try: glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, w, h, 0, self.texture_pixel_format, GL_UNSIGNED_BYTE, None) except Exception as e: log.error( "Error: cannot initialize %ix%i %s texture", w, h, CONSTANT_TO_PIXEL_FORMAT.get(self.texture_pixel_format, self.texture_pixel_format)) log.error(" %r", e) log("%s", self.gl_init, exc_info=True) raise Exception("cannot initialize %ix%i %s texture: %r" % (w, h, CONSTANT_TO_PIXEL_FORMAT.get( self.texture_pixel_format, self.texture_pixel_format), e)) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glClear(GL_COLOR_BUFFER_BIT) # Create and assign fragment programs if not self.shaders: self.gl_init_shaders() # Bind program 0 for YUV painting by default glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER]) self.gl_setup = True
def do_present_fbo(self): self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() bw, bh = self.size ww, wh = self.render_size if self.glconfig.is_double_buffered() or bw!=ww or bh!=wh: #refresh the whole window: rectangles = ((0, 0, bw, bh), ) else: #paint just the rectangles we have accumulated: rectangles = self.pending_fbo_paint self.pending_fbo_paint = [] log("do_present_fbo: painting %s", rectangles) glEnable(GL_TEXTURE_RECTANGLE_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) #viewport for painting to window: glViewport(0, 0, ww, wh) if ww!=bw or wh!=bh: glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glBegin(GL_QUADS) for x,y,w,h in rectangles: #note how we invert coordinates.. tx1, ty1, tx2, ty2 = x, bh-y, x+w, bh-y-h vx1, vy1, vx2, vy2 = x, y, x+w, y+h glTexCoord2i(tx1, ty1) glVertex2i(vx1, vy1) #top-left of window viewport glTexCoord2i(tx1, ty2) glVertex2i(vx1, vy2) #bottom-left of window viewport glTexCoord2i(tx2, ty2) glVertex2i(vx2, vy2) #bottom-right of window viewport glTexCoord2i(tx2, ty1) glVertex2i(vx2, vy1) #top-right of window viewport glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) if self.paint_spinner: #add spinner: dim = min(bw/3.0, bh/3.0) t = time.time() count = int(t*4.0) bx = bw//2 by = bh//2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count%8][i] glColor4f(c, c, c, 1) mi1 = math.pi*i/4-math.pi/16 mi2 = math.pi*i/4+math.pi/16 glVertex2i(int(bx+math.sin(mi1)*10), int(by+math.cos(mi1)*10)) glVertex2i(int(bx+math.sin(mi1)*dim), int(by+math.cos(mi1)*dim)) glVertex2i(int(bx+math.sin(mi2)*dim), int(by+math.cos(mi2)*dim)) glVertex2i(int(bx+math.sin(mi2)*10), int(by+math.cos(mi2)*10)) glEnd() #if desired, paint window border if self.border and self.border.shown: #double size since half the line will be off-screen glLineWidth(self.border.size*2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px,py in ((0, 0), (bw, 0), (bw, bh), (0, bh)): glVertex2i(px, py) glEnd() # Show the backbuffer on screen self.gl_show() self.gl_frame_terminator() #restore pbo viewport glViewport(0, 0, bw, bh) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST) self.unset_rgb_paint_state() log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.do_present_fbo() done", self)
def do_present_fbo(self): bw, bh = self.size ww, wh = self.render_size self.gl_marker("Presenting FBO on screen") # Change state to target screen instead of our FBO glBindFramebuffer(GL_FRAMEBUFFER, 0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) if self._alpha_enabled: # transparent background: glClearColor(0.0, 0.0, 0.0, 0.0) else: # plain white no alpha: glClearColor(1.0, 1.0, 1.0, 1.0) # Draw FBO texture on screen self.set_rgb_paint_state() rect_count = len(self.pending_fbo_paint) if self.glconfig.is_double_buffered() or bw != ww or bh != wh: #refresh the whole window: rectangles = ((0, 0, bw, bh), ) else: #paint just the rectangles we have accumulated: rectangles = self.pending_fbo_paint self.pending_fbo_paint = [] log("do_present_fbo: painting %s", rectangles) glEnable(GL_TEXTURE_RECTANGLE_ARB) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) if self._alpha_enabled: # support alpha channel if present: glEnablei(GL_BLEND, self.textures[TEX_FBO]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) if SAVE_BUFFERS: glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO]) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0) glReadBuffer(GL_COLOR_ATTACHMENT0) glViewport(0, 0, bw, bh) from OpenGL.GL import glGetTexImage size = bw * bh * 4 import numpy data = numpy.empty(size) img_data = glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data) from PIL import Image, ImageOps img = Image.frombuffer("RGBA", (bw, bh), img_data, "raw", "BGRA", bw * 4) img = ImageOps.flip(img) kwargs = {} if SAVE_BUFFERS == "jpeg": kwargs = { "quality": 0, "optimize": False, } t = time.time() tstr = time.strftime("%H-%M-%S", time.localtime(t)) filename = "./W%i-FBO-%s.%03i.%s" % (self.wid, tstr, (t * 1000) % 1000, SAVE_BUFFERS) log("do_present_fbo: saving %4ix%-4i pixels, %7i bytes to %s", bw, bh, size, filename) img.save(filename, SAVE_BUFFERS, **kwargs) glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) #viewport for painting to window: x, _, _, y = self.offsets glViewport(x, y, ww, wh) if ww != bw or wh != bh: glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glBegin(GL_QUADS) for x, y, w, h in rectangles: #note how we invert coordinates.. tx1, ty1, tx2, ty2 = x, bh - y, x + w, bh - y - h vx1, vy1, vx2, vy2 = x, y, x + w, y + h glTexCoord2i(tx1, ty1) glVertex2i(vx1, vy1) #top-left of window viewport glTexCoord2i(tx1, ty2) glVertex2i(vx1, vy2) #bottom-left of window viewport glTexCoord2i(tx2, ty2) glVertex2i(vx2, vy2) #bottom-right of window viewport glTexCoord2i(tx2, ty1) glVertex2i(vx2, vy1) #top-right of window viewport glEnd() glDisable(GL_TEXTURE_RECTANGLE_ARB) if self.paint_spinner: #add spinner: dim = min(bw / 3.0, bh / 3.0) t = time.time() count = int(t * 4.0) bx = bw // 2 by = bh // 2 for i in range(8): #8 lines glBegin(GL_POLYGON) c = cv.trs[count % 8][i] glColor4f(c, c, c, 1) mi1 = math.pi * i / 4 - math.pi / 16 mi2 = math.pi * i / 4 + math.pi / 16 glVertex2i(int(bx + math.sin(mi1) * 10), int(by + math.cos(mi1) * 10)) glVertex2i(int(bx + math.sin(mi1) * dim), int(by + math.cos(mi1) * dim)) glVertex2i(int(bx + math.sin(mi2) * dim), int(by + math.cos(mi2) * dim)) glVertex2i(int(bx + math.sin(mi2) * 10), int(by + math.cos(mi2) * 10)) glEnd() #if desired, paint window border if self.border and self.border.shown: #double size since half the line will be off-screen glLineWidth(self.border.size * 2) glBegin(GL_LINE_LOOP) glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha) for px, py in ((0, 0), (bw, 0), (bw, bh), (0, bh)): glVertex2i(px, py) glEnd() if self.pointer_overlay: x, y, _, _, size, start_time = self.pointer_overlay elapsed = time.time() - start_time if elapsed < 6: alpha = max(0, (5.0 - elapsed) / 5.0) glLineWidth(1) glBegin(GL_LINES) glColor4f(0, 0, 0, alpha) glVertex2i(x - size, y) glVertex2i(x + size, y) glVertex2i(x, y - size) glVertex2i(x, y + size) glEnd() else: self.pointer_overlay = None # Show the backbuffer on screen self.gl_show(rect_count) self.gl_frame_terminator() #restore pbo viewport glViewport(0, 0, bw, bh) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST) self.unset_rgb_paint_state() log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo) glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo) log("%s.do_present_fbo() done", self)