예제 #1
0
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()
예제 #2
0
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()
예제 #3
0
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
예제 #4
0
파일: yuvvideo.py 프로젝트: dev-life/yuvist
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
예제 #5
0
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()
예제 #6
0
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
예제 #7
0
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