class KinectViewer(Widget): depth_range = NumericProperty(7.7) shader = StringProperty("rgb") index = NumericProperty(0) def __init__(self, **kwargs): # change the default canvas to RenderContext, we can change the shader self.canvas = RenderContext() self.canvas.shader.fs = hsv_kinect # add kinect depth provider, and start the thread self.kinect = KinectDepth() self.kinect.start() # parent init super(KinectViewer, self).__init__(**kwargs) # allocate texture for pushing depth self.texture = Texture.create(size=(640, 480), colorfmt='luminance', bufferfmt='ushort') self.texture.flip_vertical() # create default canvas element with self.canvas: Color(1, 1, 1) Rectangle(size=Window.size, texture=self.texture) # add a little clock to update our glsl Clock.schedule_interval(self.update_transformation, 0) def on_index(self, instance, value): self.kinect.index = value def on_shader(self, instance, value): if value == 'rgb': self.canvas.shader.fs = rgb_kinect elif value == 'hsv': self.canvas.shader.fs = hsv_kinect elif value == 'points': self.canvas.shader.fs = points_kinect def update_transformation(self, *largs): # update projection mat and uvsize self.canvas['projection_mat'] = Window.render_context['projection_mat'] self.canvas['depth_range'] = self.depth_range self.canvas['size'] = list(map(float, self.size)) try: value = self.kinect.pop() except: return f = value[0].astype('ushort') * 32 self.texture.blit_buffer(f.tostring(), colorfmt='luminance', bufferfmt='ushort') self.canvas.ask_update()
class KinectViewer(Widget): depth_range = NumericProperty(7.7) shader = StringProperty("rgb") index = NumericProperty(0) def __init__(self, **kwargs): # change the default canvas to RenderContext, we can change the shader self.canvas = RenderContext() self.canvas.shader.fs = hsv_kinect # add kinect depth provider, and start the thread self.kinect = KinectDepth() self.kinect.start() # parent init super(KinectViewer, self).__init__(**kwargs) # allocate texture for pushing depth self.texture = Texture.create( size=(640, 480), colorfmt='luminance', bufferfmt='ushort') self.texture.flip_vertical() # create default canvas element with self.canvas: Color(1, 1, 1) Rectangle(size=Window.size, texture=self.texture) # add a little clock to update our glsl Clock.schedule_interval(self.update_transformation, 0) def on_index(self, instance, value): self.kinect.index = value def on_shader(self, instance, value): if value == 'rgb': self.canvas.shader.fs = rgb_kinect elif value == 'hsv': self.canvas.shader.fs = hsv_kinect elif value == 'points': self.canvas.shader.fs = points_kinect def update_transformation(self, *largs): # update projection mat and uvsize self.canvas['projection_mat'] = Window.render_context['projection_mat'] self.canvas['depth_range'] = self.depth_range self.canvas['size'] = map(float, self.size) try: value = self.kinect.pop() except: return f = value[0].astype('ushort') * 32 self.texture.blit_buffer( f.tostring(), colorfmt='luminance', bufferfmt='ushort') self.canvas.ask_update()
class YuvVideo(Video): FS_CONVERT_RGB = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float r, g, b; r = texture2D(tex_y, tex_coord0).r; g = texture2D(tex_y, tex_coord0).g; b = texture2D(tex_y, tex_coord0).b; gl_FragColor = vec4(r, g, b, 1.0); } ''' FS_CONVERT_YUV = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float r, g, b, y, u, v; y = texture2D(tex_y, tex_coord0).s; u = texture2D(tex_u, tex_coord0).s; v = texture2D(tex_v, tex_coord0).s; y = 1.1643 * (y - 0.0625); u = u - 0.5; v = v - 0.5; r = y + 1.5958 * v; g = y - 0.39173 * u - 0.81290 * v; b = y + 2.017 * u; gl_FragColor = vec4(r, g, b, 1.0); } ''' FS_CONVERT_MONO = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float y; y = texture2D(tex_y, tex_coord0).s; y = 1.1643 * (y - 0.0625); gl_FragColor = vec4(y, y, y, 1.0); } ''' fs = StringProperty(None) textures = ListProperty([None, None, None]) format = OptionProperty(YUV_CHROMA_FORMAT[1], options=YUV_CHROMA_FORMAT) colorfmt = OptionProperty(OUT_COLOR_FORMAT[1], options=OUT_COLOR_FORMAT) yuv_size = ListProperty([0, 0]) yuv_fps = NumericProperty(30.) def __init__(self, **kwargs): self.register_event_type('on_load') self.canvas = RenderContext(fs=self.FS_CONVERT_YUV) self.canvas['tex_y'] = 1 self.canvas['tex_u'] = 2 self.canvas['tex_v'] = 3 super(YuvVideo, self).__init__(**kwargs) if self.colorfmt == OUT_COLOR_FORMAT[0]: self.fs = self.FS_CONVERT_RGB elif self.format != YUV_CHROMA_FORMAT[0]: self.fs = self.FS_CONVERT_YUV else: self.fs = self.FS_CONVERT_MONO def seek(self, percent): if self.eos == True: self.eos = False super(YuvVideo, self).seek(percent) def on_load(self, *largs): pass def on_fs(self, instance, value): shader = self.canvas.shader old_value = shader.fs shader.fs = value if not shader.success: shader.fs = old_value raise Exception('failed') def on_size(self, instance, value): window = self.get_parent_window() if window: self.canvas['projection_mat'] = window.render_context[ 'projection_mat'] def on_state(self, instance, value): if not self._video: return if value == 'stop': self._video.stop() else: super(YuvVideo, self).on_state(instance, value) def _do_video_load(self, *largs): if self._video: self._video.stop() if not self.source: self._video = None self.textures = [None, None, None] self.texture = None else: filename = self.source if filename.split(':')[0] not in ('http', 'https', 'file', 'udp', 'rtp', 'rtsp'): filename = resource_find(filename) self._video = VideoYuv(filename=filename, format=self.format, colorfmt=self.colorfmt, size=self.yuv_size, fps=self.yuv_fps) self._video.volume = self.volume self._video.bind(on_load=self._on_video_load, on_frame=self._on_video_frame, on_eos=self._on_eos) if self.state == 'play' or self.play: self._video.play() self.duration = 1. self.position = 0. def _on_video_load(self, *largs): self._on_video_frame() self.dispatch('on_load') def _on_video_frame(self, *largs): self.duration = self._video.duration self.position = self._video.position self.textures = self._video.texture self.texture = self._video.texture[0] self.canvas.ask_update() def _on_eos(self, *largs): self.duration = self._video.duration self.position = self._video.position self.state = 'pause' self.eos = True
class YuvVideo(Video): FS_CONVERT_RGB = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float r, g, b; r = texture2D(tex_y, tex_coord0).r; g = texture2D(tex_y, tex_coord0).g; b = texture2D(tex_y, tex_coord0).b; gl_FragColor = vec4(r, g, b, 1.0); } ''' FS_CONVERT_YUV = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float r, g, b, y, u, v; y = texture2D(tex_y, tex_coord0).s; u = texture2D(tex_u, tex_coord0).s; v = texture2D(tex_v, tex_coord0).s; y = 1.1643 * (y - 0.0625); u = u - 0.5; v = v - 0.5; r = y + 1.5958 * v; g = y - 0.39173 * u - 0.81290 * v; b = y + 2.017 * u; gl_FragColor = vec4(r, g, b, 1.0); } ''' FS_CONVERT_MONO = '''$HEADER$ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) { float y; y = texture2D(tex_y, tex_coord0).s; y = 1.1643 * (y - 0.0625); gl_FragColor = vec4(y, y, y, 1.0); } ''' fs = StringProperty(None) textures = ListProperty([None, None, None]) format = OptionProperty(YUV_CHROMA_FORMAT[1], options=YUV_CHROMA_FORMAT) colorfmt = OptionProperty(OUT_COLOR_FORMAT[1], options=OUT_COLOR_FORMAT) yuv_size = ListProperty([0, 0]) yuv_fps = NumericProperty(30.) def __init__(self, **kwargs): self.register_event_type('on_load') self.canvas = RenderContext(fs=self.FS_CONVERT_YUV) self.canvas['tex_y'] = 1 self.canvas['tex_u'] = 2 self.canvas['tex_v'] = 3 super(YuvVideo, self).__init__(**kwargs) if self.colorfmt == OUT_COLOR_FORMAT[0]: self.fs = self.FS_CONVERT_RGB elif self.format != YUV_CHROMA_FORMAT[0]: self.fs = self.FS_CONVERT_YUV else: self.fs = self.FS_CONVERT_MONO def seek(self, percent): if self.eos == True: self.eos = False super(YuvVideo, self).seek(percent) def on_load(self, *largs): pass def on_fs(self, instance, value): shader = self.canvas.shader old_value = shader.fs shader.fs = value if not shader.success: shader.fs = old_value raise Exception('failed') def on_size(self, instance, value): window = self.get_parent_window() if window: self.canvas['projection_mat'] = window.render_context['projection_mat'] def on_state(self, instance, value): if not self._video: return if value == 'stop': self._video.stop() else: super(YuvVideo, self).on_state(instance, value) def _do_video_load(self, *largs): if self._video: self._video.stop() if not self.source: self._video = None self.textures = [None, None, None] self.texture = None else: filename = self.source if filename.split(':')[0] not in ( 'http', 'https', 'file', 'udp', 'rtp', 'rtsp'): filename = resource_find(filename) self._video = VideoYuv(filename=filename, format=self.format, colorfmt=self.colorfmt, size=self.yuv_size, fps=self.yuv_fps) self._video.volume = self.volume self._video.bind(on_load=self._on_video_load, on_frame=self._on_video_frame, on_eos=self._on_eos) if self.state == 'play' or self.play: self._video.play() self.duration = 1. self.position = 0. def _on_video_load(self, *largs): self._on_video_frame() self.dispatch('on_load') def _on_video_frame(self, *largs): self.duration = self._video.duration self.position = self._video.position self.textures = self._video.texture self.texture = self._video.texture[0] self.canvas.ask_update() def _on_eos(self, *largs): self.duration = self._video.duration self.position = self._video.position self.state = 'pause' self.eos = True
class AndroidCameraPreview(Image): """ Android camera preview widget. Extends Image with a custom shader that displays textures of target GL_TEXTURE_EXTERNAL_OES. Note, this requires Android API 11 because of it's use of SurfaceTexture. """ play = BooleanProperty(False) resolution = ListProperty([720, 720]) camera_id = NumericProperty(-1) _camera = None _previewCallback = None _previewTexture = None _previewSurface = None _secondary_texture = None def __init__(self, **kwargs): self.canvas = RenderContext() super(AndroidCameraPreview, self).__init__(**kwargs) self.bind(resolution=self._resolution_changed) self.bind(camera_id=self._camera_id_changed) self.bind(play=self._play_changed) # This is needed for the default vertex shader. self.canvas['projection_mat'] = Window.render_context['projection_mat'] with self.canvas: Callback(self._draw_callback) BindTexture(texture=self._secondary_texture, index=1) self.canvas['secondary_texture'] = 1 self._init_texture(self.resolution) def start(self, play=True): self._init_camera(self.camera_id) self.play = play def stop(self): self._release_camera() def _init_texture(self, resolution): width, height = resolution # Image looks at self.texture to determine layout, so we create # texture but don't actually display it. self.texture = Texture.create(size=(height, width)) self.texture_size = self.texture.size if IsAndroid: self._secondary_texture = Texture(width=height, height=width, target=GL_TEXTURE_EXTERNAL_OES, colorfmt='rgba') self._secondary_texture.bind() self._previewTexture = SurfaceTexture(int(self._secondary_texture.id)) def _init_camera(self, camera_id): Logger.info('Init camera %d' % camera_id) if self._camera and self.camera_id == camera_id: return self._release_camera() if IsAndroid: self._camera = Camera.open(camera_id) parameters = self._camera.getParameters() #print parameters.flatten() if parameters is None: Logger.warning('Can''t read parameters') return supportedSizes = parameters.getSupportedVideoSizes() if supportedSizes is None: supportedSizes = parameters.getSupportedPreviewSizes() sizes = [] if supportedSizes is not None: iterator = supportedSizes.iterator() while iterator.hasNext(): cameraSize = iterator.next() sizes.append((cameraSize.width, cameraSize.height)) pickedSize = self._pick_optimal_size(sizes) # Update texture according to picked size self.resolution = list(pickedSize) parameters.setPreviewSize(*pickedSize) self._camera.setParameters(parameters) self._camera.setPreviewTexture(self._previewTexture) def get_camera(self): return self._camera def _resolution_changed(self, instance, value): Logger.info('Resolution changed to ' + str(value)) self._init_texture(value) def _camera_id_changed(self, instance, value): Logger.info('Changed camera %d' % value) if not IsAndroid: return # Transform orientation based on selected camera if self.camera_id == 0: sampleVec = ('1.0-tex_coord0.y','1.0-tex_coord0.x') elif self.camera_id == 1: sampleVec = ('tex_coord0.y','1.0-tex_coord0.x') else: raise Exception('Invalid camera id') self.canvas.shader.fs = ''' #extension GL_OES_EGL_image_external : require #ifdef GL_ES precision highp float; #endif /* Outputs from the vertex shader */ varying vec4 frag_color; varying vec2 tex_coord0; /* uniform texture samplers */ uniform sampler2D texture0; uniform samplerExternalOES texture1; void main() { // Flip & Mirror coordinates to rotate source texture by 90 degress gl_FragColor = texture2D(texture1, vec2(%s,%s)); } ''' % (sampleVec[0], sampleVec[1]) def _play_changed(self, instance, value): Logger.info('camera %d _play_changed %d' % (self.camera_id, value)) if not IsAndroid: return if value: if not self._camera: self._init_camera(self.camera_id) self._camera.startPreview() Clock.schedule_interval(self._update_canvas, 1.0/30) else: if self._camera: Clock.unschedule(self._update_canvas) self._camera.stopPreview() def _release_camera(self): self.play = False if self._camera: self._camera.release() self._camera = None def _pick_optimal_size(self, sizes): # Now just returns the one guaranteed support size return sizes[0] def _draw_callback(self, instr): if self._previewTexture: self._previewTexture.updateTexImage() def _update_canvas(self, dt): self.canvas.ask_update()
class XWindow(Widget): __events__ = [ 'on_window_map', 'on_window_resize', 'on_window_unmap', 'on_window_destroy', ] active = BooleanProperty(False) invalidate_pixmap = BooleanProperty(False) pixmap = ObjectProperty(None, allownone=True) refresh_rate = NumericProperty() texture = ObjectProperty(None, allownone=True) def __init__(self, manager, window=None, **kwargs): super().__init__(**kwargs) self.manager = manager if window: self._window = window else: self._window = manager.screen.root.create_window( x=0, y=0, width=self.width, height=self.height, depth=self.manager.screen.root_depth, border_width=0, window_class=Xlib.X.InputOutput, visual=Xlib.X.CopyFromParent, ) refresh_hz = int(os.environ.get('KIVYWM_REFRESH_HZ', 60)) self.refresh_rate = 1 / refresh_hz if refresh_hz > 0 else 0 self.canvas = RenderContext(use_parent_projection=True, use_parent_modelview=True, use_parent_frag_modelview=True) with self.canvas: self.rect = Rectangle(size=self.size) def __repr__(self): if hasattr(self, '_window') and self._window is not None: return f'<{self.__class__.__name__} id: {hex(self.id)}>' else: return f'<{self.__class__.__name__} (No Window Bound)>' def focus(self): self._win.set_input_focus(revert_to=Xlib.X.RevertToParent, time=Xlib.X.CurrentTime) def redraw(self, *args): self.canvas.ask_update() return self.active def on_invalidate_pixmap(self, *args): if not self.invalidate_pixmap or not self._window: return try: self.release_texture() self.release_pixmap() self.create_pixmap() self.create_texture() except (Xlib.error.BadDrawable, Xlib.error.BadWindow, KeyboardInterrupt): self.active = False self.invalidate_pixmap = False def on_active(self, *args): if self.active: Clock.schedule_interval(self.redraw, self.refresh_rate) else: self.release_texture() self.release_pixmap() def map(self, *args): try: self._window.map() except AttributeError: pass self.invalidate_pixmap = True self.start() def unmap(self, *args): try: self._window.unmap() except AttributeError: pass self.stop() def start(self, *args): self.active = True def stop(self, *args): self.active = False def destroy(self, *args, **kwargs): window = self._window self._window = None self.active = False self.unmap() self.release_texture() self.release_pixmap() self.canvas.clear() window.destroy() @property def id(self): try: return self._window.id except AttributeError: return None def on_size(self, *args): Logger.trace(f'WindowMgr: {self}: on_size: {self.size}') try: self._window.configure( width=round(self.width), height=round(self.height), ) except AttributeError: return self.invalidate_pixmap = True def on_pos(self, *args): try: self._window.configure( x=round(self.x), y=round(self.y), ) except AttributeError: return def on_window_map(self): Logger.trace(f'WindowMgr: {self}: on_window_map') self.invalidate_pixmap = True def on_window_resize(self): Logger.trace(f'WindowMgr: {self}: on_window_resize') self.invalidate_pixmap = True def on_window_unmap(self): Logger.trace(f'WindowMgr: {self}: on_window_unmap') self.stop() def on_window_destroy(self): Logger.trace(f'WindowMgr: {self}: on_window_destroy') def create_pixmap(self): ec = Xlib.error.CatchError(Xlib.error.BadMatch) try: self.pixmap = self._window.composite_name_window_pixmap(onerror=ec) except AttributeError: pass if ec.get_error(): self.pixmap = None def release_pixmap(self): if self.pixmap: self.pixmap.free() self.pixmap = None def create_texture(self): if not self._window: return try: geom = self._window.get_geometry() self.texture = Texture.create_from_pixmap( self.pixmap.id, (geom.width, geom.height)) except AttributeError: return else: self.rect.texture = self.texture self.rect.size = self.texture.size def release_texture(self): self.texture = None
class SMAA(Widget): debug = OptionProperty("", options=("", "edges", "blend", "source")) """Texture to show instead of the result: - `edges` will show you the result of the edges detection shader - `blend` will show you the result of the blending shader - `source` will show you the initial drawing of children, before any pass. """ quality = OptionProperty("ultra", options=("low", "medium", "high", "ultra")) """Quality of the shader. The more you ask, the slower it will be. """ def __init__(self, **kwargs): self._g_debug = [] self._g_debug_added = False if "size" not in kwargs: from kivy.core.window import Window kwargs["size"] = Window.size self.size = kwargs["size"] self.init_smaa() super(SMAA, self).__init__() self.canvas.add(self.smaa_canvas) self.canvas.ask_update() def add_widget(self, *args): canvas = self.smaa_canvas self.canvas = self.albedo_fbo super(SMAA, self).add_widget(*args) self.canvas = canvas def remove_widget(self, *args): canvas = self.smaa_canvas self.canvas = self.albedo_fbo super(SMAA, self).remove_widget(*args) self.canvas = canvas def init_smaa(self): curdir = dirname(__file__) # load shaders sources with open(join(curdir, "SMAA.h"), "r") as fd: smaa_h = fd.read() config = """ #version 410 compatibility #define SMAA_PIXEL_SIZE vec2(1.0 / {width}, 1.0 / {height}) #define SMAA_PRESET_{quality} 1 #define SMAA_GLSL_4 1 """.format( width=self.width, height=self.height, quality=self.quality.upper() ) header_vs = ( config + """ #define SMAA_ONLY_COMPILE_VS 1 in vec2 vPosition; in vec2 vTexCoords0; uniform mat4 modelview_mat; uniform mat4 projection_mat; """ + smaa_h ) header_fs = ( config + """ #define SMAA_ONLY_COMPILE_PS 1 """ + smaa_h ) edge_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAAEdgeDetectionVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) edge_fs = ( header_fs + """ uniform sampler2D albedo_tex; in vec2 texcoord; in vec4 offset[3]; in vec4 dummy2; void main() { #if SMAA_PREDICATION == 1 gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex, depthTex); #else gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex); #endif } """ ) blend_vs = ( header_vs + """ out vec2 texcoord; out vec2 pixcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAABlendingWeightCalculationVS(dummy1, dummy2, texcoord, pixcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) blend_fs = ( header_fs + """ uniform sampler2D edge_tex; uniform sampler2D area_tex; uniform sampler2D search_tex; in vec2 texcoord; in vec2 pixcoord; in vec4 offset[3]; in vec4 dummy2; void main() { gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edge_tex, area_tex, search_tex, ivec4(0)); } """ ) neighborhood_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[2]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAANeighborhoodBlendingVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) neighborhood_fs = ( header_fs + """ uniform sampler2D albedo_tex; uniform sampler2D blend_tex; in vec2 texcoord; in vec4 offset[2]; in vec4 dummy2; void main() { gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, albedo_tex, blend_tex); } """ ) size = self.size self.albedo_tex = Texture.create(size=size, bufferfmt="float") self.albedo_fbo = Fbo(size=size, texture=self.albedo_tex) self.edge_tex = Texture.create(size=size, bufferfmt="float") self.edge_fbo = Fbo(size=size, vs=edge_vs, fs=edge_fs, texture=self.edge_tex) self.edge_fbo.bind() self.edge_fbo["albedo_tex"] = 0 self.edge_fbo.release() self.blend_tex = Texture.create(size=size, bufferfmt="float") self.blend_fbo = Fbo(size=size, vs=blend_vs, fs=blend_fs, texture=self.blend_tex) self.blend_fbo.bind() self.blend_fbo["edge_tex"] = 0 self.blend_fbo["area_tex"] = 1 self.blend_fbo["search_tex"] = 2 self.blend_fbo.release() self.neighborhood = RenderContext( use_parent_modelview=True, use_parent_projection=True, vs=neighborhood_vs, fs=neighborhood_fs ) with self.neighborhood: self.neighborhood["albedo_tex"] = 0 self.neighborhood["blend_tex"] = 1 self.area_tex = Texture.create(size=(AREATEX_WIDTH, AREATEX_HEIGHT), colorfmt="rg", icolorfmt="rg8") with open(join(curdir, "smaa_area.raw"), "rb") as fd: self.area_tex.blit_buffer(fd.read(), colorfmt="rg") self.search_tex = Texture.create(size=(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT), colorfmt="red", icolorfmt="r8") self.search_tex.min_filter = "nearest" self.search_tex.mag_filter = "nearest" with open(join(curdir, "smaa_search.raw"), "rb") as fd: self.search_tex.blit_buffer(fd.read(), colorfmt="red") with self.albedo_fbo: ClearColor(0, 0, 0, 0) ClearBuffers() with self.edge_fbo: Rectangle(size=self.size, texture=self.albedo_tex) with self.blend_fbo: BindTexture(index=1, texture=self.area_tex) BindTexture(index=2, texture=self.search_tex) Rectangle(size=self.size, texture=self.edge_tex) self.neighborhood.add(self.albedo_fbo) self.neighborhood.add(Callback(lambda *x: glDisable(GL_BLEND))) self.neighborhood.add(self.edge_fbo) self.neighborhood.add(self.blend_fbo) self.neighborhood.add(Callback(lambda *x: glEnable(GL_BLEND))) with self.neighborhood: BindTexture(index=1, texture=self.blend_tex) Rectangle(size=self.size, texture=self.albedo_tex) self.smaa_canvas = Canvas() with self.smaa_canvas.before: def do_stuff(*args): self.albedo_fbo.bind() self.albedo_fbo.clear_buffer() self.albedo_fbo.release() self.edge_fbo.bind() self.edge_fbo.clear_buffer() self.edge_fbo.release() self.blend_fbo.bind() self.blend_fbo.clear_buffer() self.blend_fbo.release() self.albedo_fbo.ask_update() self.edge_fbo.ask_update() self.blend_fbo.ask_update() self.neighborhood.ask_update() Callback(do_stuff) self.smaa_canvas.add(self.neighborhood) self._g_debug_added = False self._g_debug = [ Callback(lambda *x: glDisable(GL_BLEND)), Color(0, 0, 0, 1), Rectangle(size=self.size), Color(1, 1, 1, 1), Rectangle(size=self.size), Callback(lambda *x: glEnable(GL_BLEND)), ] def on_debug(self, instance, value): g_debug = self._g_debug if self._g_debug_added: for instr in g_debug: self.canvas.after.remove(instr) if value == "": return elif value == "edges": g_debug[-2].texture = self.edge_tex elif value == "blend": g_debug[-2].texture = self.blend_tex elif value == "source": g_debug[-2].texture = self.albedo_tex self._g_debug_added = True for instr in g_debug: self.canvas.after.add(instr) def on_quality(self, instance, value): self.reload_smaa() def reload_smaa(self): debug = self.debug self.debug = "" children = self.children[:] for child in children: self.remove_widget(child) self.canvas.remove(self.smaa_canvas) self.init_smaa() self.canvas.add(self.smaa_canvas) for child in children: self.add_widget(child) self.debug = debug