class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects['Sphere'] _set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) _draw_element(sphere) # Then draw other elements and totate it in different axis pyramid = self.scene.objects['Pyramid'] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0., 0., .7, id_color=(0., 0., 255)) _draw_element(pyramid) PopMatrix() box = self.scene.objects['Box'] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(.7, 0., 0., id_color=(255, 0., 0)) _draw_element(box) PopMatrix() cylinder = self.scene.objects['Cylinder'] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, .7, 0., id_color=(0., 255, 0)) _draw_element(cylinder) PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print self.fbo.get_pixel_color(touch.x, touch.y) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class NSpect(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): LOP, dm = initFiles() #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.LOP = LOP self.dm = dm self.meshes = [] self.panCamera = False # KEITH EDIT self.pause = True # KEITH EDIT with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* # Keith: This allows keyboard interaction # http://stackoverflow.com/questions/22137786/ self._keyboard = Window.request_keyboard(None, self) if not self._keyboard: return self._keyboard.bind(on_key_down=self.on_keyboard_down) # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* super(NSpect, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene(self.LOP, dm) PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self, LOP, dm): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements(LOP, dm) PopMatrix() def draw_elements(self, LOP, dm): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) def drawPoints(): print self.scene.objects for i in range(len(self.LOP)): PushMatrix() point = self.LOP[i] point.shape = self.scene.objects['Sphere'] point.color = _set_color(i/10., (i+1)/10., 0., id_color=(int(255/(1+i)), int(255/(1+i)), 255)) point.shape.scale = Scale((i+1)/10.0,(i+1)/10.0,(i+1)/10.0) self.LOP[i] = point print point.shape _draw_element(point.shape) point.shape.scale.origin = (point.loc[0],point.loc[1],point.loc[2]) PopMatrix() drawPoints() def update_scene(self, *largs): def randLoc(point): newLoc = (0.1*random.random(),0.1*random.random(),0.1*random.random()) oldLoc = point.shape.scale.origin newLoc = ( newLoc[0]-0.05+oldLoc[0], newLoc[1]-0.05+oldLoc[1], newLoc[2]-0.05+oldLoc[2] ) return newLoc def updateLocs(self): for i in range(len(self.LOP)): point = self.LOP[i] point.shape.scale.origin = randLoc(point) if not self.pause: updateLocs(self) pass # =============== All stuff after is for trackball implementation ============= def moveA(self): pass def moveB(self): pass def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print self.fbo.get_pixel_color(touch.x, touch.y) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() # *O(U(U())(*U(*(****************** # Keith: This allows keyboard interaction def on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'left': if self.panCamera == True: self.x -= 10 else: self.roty.angle += 10 elif keycode[1] == 'right': if self.panCamera == True: self.x += 10 else: self.roty.angle -= 10 if keycode[1] == 'up': if self.panCamera == True: self.y += 10 else: self.rotx.angle += 10 elif keycode[1] == 'down': if self.panCamera == True: self.y -= 10 else: self.rotx.angle -= 10 elif keycode[1] == 'i': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz) elif keycode[1] == 'o': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: temp = tuple(p - scale for p in xyz) # Prevent the collection from having a negative size if temp[0] > 0: self.scale.xyz = temp elif keycode[1] == 't': self.panCamera = not self.panCamera elif keycode[1] == 'p': self.pause = not self.pause if not self.pause: print "Playing" else: print "Paused" def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects['Sphere'] _set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) _draw_element(sphere) # Then draw other elements and totate it in different axis pyramid = self.scene.objects['Pyramid'] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0., 0., .7, id_color=(0., 0., 255)) _draw_element(pyramid) PopMatrix() box = self.scene.objects['Box'] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(.7, 0., 0., id_color=(255, 0., 0)) _draw_element(box) PopMatrix() cylinder = self.scene.objects['Cylinder'] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, .7, 0., id_color=(0., 255, 0)) _draw_element(cylinder) PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print(self.fbo.get_pixel_color(touch.x, touch.y)) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
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