Esempio n. 1
0
def widgetshot(widget, filename='output.png'):
    # detach the widget from the parent
    parent = widget.parent
    if parent:
        parent.remove_widget(widget)

    # put the widget canvas on a Fbo
    texture = Texture.create(size=widget.size, colorfmt='rgb')
    fbo = Fbo(size=widget.size, texture=texture)
    fbo.add(widget.canvas)

    # clear the fbo background
    fbo.bind()
    fbo.clear_buffer()
    fbo.release()

    # draw!
    fbo.draw()

    # get the fbo data
    fbo.bind()
    data = glReadPixels(0, 0, widget.size[0], widget.size[1], GL_RGBA,
                        GL_UNSIGNED_BYTE)
    fbo.release()

    # save to a file
    surf = pygame.image.fromstring(data, widget.size, 'RGBA', True)
    pygame.image.save(surf, filename)

    # reattach to the parent
    if parent:
        parent.add_widget(widget)

    return True
Esempio n. 2
0
def widgetshot(widget, filename='output.png'): 
# detach the widget from the parent 
    parent = widget.parent
    if parent:
        parent.remove_widget(widget)

    # put the widget canvas on a Fbo
    texture = Texture.create(size=widget.size, colorfmt='rgb')
    fbo = Fbo(size=widget.size, texture=texture)
    fbo.add(widget.canvas)

    # clear the fbo background
    fbo.bind()
    fbo.clear_buffer()
    fbo.release()

    # draw!
    fbo.draw()

    # get the fbo data
    fbo.bind()
    data = glReadPixels(0, 0, widget.size[0], widget.size[1], GL_RGBA, GL_UNSIGNED_BYTE)
    fbo.release()

    # save to a file
    surf = pygame.image.fromstring(data, widget.size, 'RGBA', True)
    pygame.image.save(surf, filename)

    # reattach to the parent
    if parent:
        parent.add_widget(widget)

    return True
Esempio n. 3
0
class Renderer(Widget):

    def __init__(self, **kw):
        self.shader_file = kw.pop("shader_file", None)
        self.canvas = Canvas()
        super(Renderer, self).__init__(**kw)

        with self.canvas:
            self._viewport = Rectangle(size=self.size, pos=self.pos)
            self.fbo = Fbo(size=self.size,
                           with_depthbuffer=True, compute_normal_mat=True)
        self._config_fbo()
        self.texture = self.fbo.texture
        self.camera = None
        self.scene = None

    def _config_fbo(self):
        # set shader file here
        self.fbo.shader.source = self.shader_file or \
                                os.path.join(kivy3_path, "default.glsl")
        with self.fbo:
            Callback(self._setup_gl_context)
            PushMatrix()
            # instructions set for all instructions
            self._instructions = InstructionGroup()
            PopMatrix()
            Callback(self._reset_gl_context)

    def _setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

    def _reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def render(self, scene, camera):
        self.scene = scene
        self.camera = camera
        self.camera.bind_to(self)
        self._instructions.add(scene.as_instructions())
        Clock.schedule_once(self._update_matrices, -1)

    def on_size(self, instance, value):
        self.fbo.size = value
        self._viewport.texture = self.fbo.texture
        self._viewport.size = value
        self._update_matrices()

    def on_texture(self, instance, value):
        self._viewport.texture = value

    def _update_matrices(self, dt=None):
        if self.camera:
            self.fbo['projection_mat'] = self.camera.projection_matrix
            self.fbo['modelview_mat'] = self.camera.modelview_matrix
        else:
            raise RendererError("Camera is not defined for renderer")

    def set_clear_color(self, color):
        self.fbo.clear_color = color
Esempio n. 4
0
class Renderer(Widget):

    def __init__(self, **kw):
        self.shader_file = kw.pop("shader_file", None)
        self.canvas = Canvas()
        super(Renderer, self).__init__(**kw)

        with self.canvas:
            self._viewport = Rectangle(size=self.size, pos=self.pos)
            self.fbo = Fbo(size=self.size,
                           with_depthbuffer=True, compute_normal_mat=True,
                           clear_color=(0., 0., 0., 0.))
        self._config_fbo()
        self.texture = self.fbo.texture
        self.camera = None
        self.scene = None

    def _config_fbo(self):
        # set shader file here
        self.fbo.shader.source = self.shader_file or \
            os.path.join(kivy3_path, "default.glsl")
        with self.fbo:
            Callback(self._setup_gl_context)
            PushMatrix()
            # instructions set for all instructions
            self._instructions = InstructionGroup()
            PopMatrix()
            Callback(self._reset_gl_context)

    def _setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

    def _reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def render(self, scene, camera):
        self.scene = scene
        self.camera = camera
        self.camera.bind_to(self)
        self._instructions.add(scene.as_instructions())
        Clock.schedule_once(self._update_matrices, -1)

    def add(self, obj):
        self._instructions.add(obj.as_instructions())

    def on_size(self, instance, value):
        self.fbo.size = value
        self._viewport.texture = self.fbo.texture
        self._viewport.size = value
        self._viewport.pos = self.pos
        self._update_matrices()

    def on_pos(self, instance, value):
        self._viewport.pos = self.pos
        self._update_matrices()

    def on_texture(self, instance, value):
        self._viewport.texture = value

    def _update_matrices(self, dt=None):
        if self.camera:
            self.fbo['projection_mat'] = self.camera.projection_matrix
            self.fbo['modelview_mat'] = self.camera.modelview_matrix
        else:
            raise RendererError("Camera is not defined for renderer")

    def set_clear_color(self, color):
        self.fbo.clear_color = color
class ObjectRenderer(Widget):
    scene = StringProperty('')
    obj_id = StringProperty('')
    obj_translation = ListProperty([0, 0, 0])
    obj_rotation = ListProperty([0, 0, 0])
    obj_scale = NumericProperty(1)
    obj_texture = StringProperty('')
    texture = ObjectProperty(None, allownone=True)
    cam_translation = ListProperty([0, 0, 0])
    cam_rotation = ListProperty([0, 0, 0])
    display_all = BooleanProperty(False)
    light_sources = DictProperty()
    ambiant = NumericProperty(.5)
    diffuse = NumericProperty(.5)
    specular = NumericProperty(.5)
    mode = StringProperty('triangles')

    def __init__(self, **kwargs):
        self.canvas = Canvas()
        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(
            join(dirname(__file__), 'simple.glsl'))
        super(ObjectRenderer, self).__init__(**kwargs)

    def on_obj_rotation(self, *args):
        self.obj_rot_x.angle = self.obj_rotation[0]
        self.obj_rot_y.angle = self.obj_rotation[1]
        self.obj_rot_z.angle = self.obj_rotation[2]

    def on_cam_rotation(self, *args):
        self.cam_rot_x.angle = self.cam_rotation[0]
        self.cam_rot_y.angle = self.cam_rotation[1]
        self.cam_rot_z.angle = self.cam_rotation[2]

    def on_obj_translation(self, *args):
        self.obj_translate.xyz = self.cam_translation

    def on_cam_translation(self, *args):
        self.cam_translate.xyz = self.cam_translation

    def on_obj_scale(self, *args):
        self.scale.xyz = [self.obj_scale, ] * 3

    def on_display_all(self, *args):
        self.setup_canvas()

    def on_light_sources(self, *args):
        self.fbo['light_sources'] = [
            ls[:] for ls in list(self.light_sources.values())]
        self.fbo['nb_lights'] = len(self.light_sources)

    def on_ambiant(self, *args):
        self.fbo['ambiant'] = self.ambiant

    def on_diffuse(self, *args):
        self.fbo['diffuse'] = self.diffuse

    def on_specular(self, *args):
        self.fbo['specular'] = self.specular

    def on_mode(self, *args):
        self.setup_canvas()

    def setup_canvas(self, *args):
        if not (self.scene and self.obj_id or self.display_all):
            return

        print('setting up the scene')
        with self.fbo:
            self.fbo['ambiant'] = self.ambiant
            self.fbo['diffuse'] = self.diffuse
            self.fbo['specular'] = self.specular
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            self.setup_scene()
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)

    def on_scene(self, instance, value):
        print("loading scene %s" % value)
        self._scene = ObjFileLoader(resource_find(value))
        self.setup_canvas()

    def on_obj_id(self, *args):
        self.setup_canvas()

    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):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def update_glsl(self, *args):
        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()
        self.cam_translate = Translate(self.cam_translation)
        # Rotate(0, 1, 0, 0)
        self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0)
        self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0)
        self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1)
        self.scale = Scale(self.obj_scale)
        UpdateNormalMatrix()
        if self.display_all:
            for i in self._scene.objects:
                self.draw_object(i)
        else:
            self.draw_object(self.obj_id)
        PopMatrix()

    def draw_object(self, obj_id):
        m = self._scene.objects[obj_id]
        self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0)
        self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0)
        self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1)
        self.obj_translate = Translate(xyz=self.obj_translation)

        if len(m.indices) > 2 ** 16:
            print('%s too big! %s indices' % (obj_id, len(m.indices)))

        if m.texture:
            print("loading texture %s " % m.texture)
            img = Image(source=resource_find(
                join(dirname(self.scene), m.texture)))
            texture = img.texture
            if texture:
                texture.wrap = 'repeat'
        else:
            texture = None

        vertex_lenght = sum(x[1] for x in m.vertex_format)
        if len(m.vertices) % vertex_lenght:
            print((
                (
                    'warning: vertices lenght (%s)'
                    'is not a multiple of vertex_format lenght(%s)'
                )
                % (len(m.vertices), vertex_lenght)))
        Mesh(
            vertices=m.vertices,
            indices=m.indices,
            fmt=m.vertex_format,
            texture=texture,
            mode=self.mode)
Esempio n. 6
0
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, 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.0)

        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, -4.75)
        # 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, texture=""):
            mesh = Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode="triangles")
            if texture:
                texture = Image(texture).texture
                mesh.texture = texture

        def _set_color(*color, **kw):
            id_color = kw.pop("id_color", (0, 0, 0))
            return ChangeState(
                Kd=color,
                Ka=color,
                Ks=(0.3, 0.3, 0.3),
                Tr=1.0,
                Ns=1.0,
                intensity=1.0,
                id_color=[i / 255.0 for i in id_color],
            )

        # Draw sphere in the center
        sphere = self.scene.objects["Sphere"]
        _set_color(0.7, 0.7, 0.0, id_color=(255, 255, 0))
        _draw_element(sphere, "rock.png")

        # 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, 0.0, 0.7, id_color=(0.0, 0.0, 255))
        _draw_element(pyramid, "rain.png")
        PopMatrix()

        box = self.scene.objects["Box"]
        PushMatrix()
        self.box_rot = Rotate(0, 0, 1, 0)
        _set_color(0.7, 0.0, 0.0, id_color=(255, 0.0, 0))
        _draw_element(box, "bricks.png")
        PopMatrix()

        cylinder = self.scene.objects["Cylinder"]
        PushMatrix()
        self.cylinder_rot = Rotate(0, 1, 0, 0)
        _set_color(0.0, 0.7, 0.0, id_color=(0.0, 255, 0))
        _draw_element(cylinder, "wood.png")
        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)

    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)
Esempio n. 7
0
class Paint(StencilView):
    scale = NumericProperty()

    def __init__(self, app, **kwargs):
        StencilView.__init__(self, **kwargs)
        self.app = app
        self.xx = 0
        self.scale = 1.0
        self.size_hint = (None, None)
        self.cursor_pos = (0, 0)
        self.fbo_size = DEFAULT_IMAGE_SIZE
        self.fbo = None
        self.fbo_rect = None
        self.tool_fbo = None
        self.tool_fbo_rect = None
        self.bg_rect = None
        self.rect = None
        self.fbo_clear_color = (1, 1, 1, 1)
        self.layer_undo_stack = []
        self.undo_layer_index = 0
        self.layer_rect = []
        self.fbo_create_on_canvas()
        self.touches = []
        self.move_image = False
        self.active_layer = None
        self.tool_buffer_enabled = True
        self.px = None
        self.py = None
        self.grid_texture = None
        self.active_layer_last_texture = None

    def grid_create(self, size):
        self.grid_texture = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte')
        tex = improc.texture_draw_grid(self.grid_texture, 255, 4)
        return tex

    def fbo_create(self, size, tex=None):
        if tex is None:
            tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte')
            tex.mag_filter = 'nearest'
            tex.min_filter = 'nearest'
        if self.fbo is None:
            self.fbo = Fbo(size=size, texture=tex)
            self.fbo.texture.mag_filter = 'nearest'
            self.fbo.texture.min_filter = 'nearest'
        else:
            self.fbo = Fbo(size=size, texture=tex)
            self.fbo.texture.mag_filter = 'nearest'
            self.fbo.texture.min_filter = 'nearest'
        tool_tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte')
        tool_tex.mag_filter = 'nearest'
        tool_tex.min_filter = 'nearest'
        if self.tool_fbo is None:
            self.tool_fbo = Fbo(size=size, texture=tool_tex)
            self.tool_fbo.texture.mag_filter = 'nearest'
            self.tool_fbo.texture.min_filter = 'nearest'
        else:
            self.tool_fbo = Fbo(size=size, texture=tool_tex)
            self.tool_fbo.texture.mag_filter = 'nearest'
            self.tool_fbo.texture.min_filter = 'nearest'
        return self.fbo

    def refbo(self):
        tex = Texture.create(size=self.fbo.texture.size, colorfmt='rgba', bufferfmt='ubyte')
        self.fbo = Fbo(size=tex.size, texture=tex)
        self.fbo.texture.mag_filter = 'nearest'
        self.fbo.texture.min_filter = 'nearest'
        self.fbo.draw()
        self.canvas.ask_update()

    def canvas_put_drawarea(self, texture=None):
        self.canvas.clear()
        if texture:
            self.fbo_size = texture.size
            self.fbo_create(texture.size, tex=texture)
        self.bg_rect = layer.Layer.layer_bg_rect
        with self.canvas:
            self.canvas.add(self.bg_rect)
            Color(1, 1, 1, 1)
            for laybox in layer.LayerBox.boxlist:
                if laybox.layer:
                    if laybox.layer.texture and laybox.layer.visible:
                        self.canvas.add(laybox.layer.rect)
                        laybox.layer.rect.pos = self.fbo_rect.pos

                if self.tool_buffer_enabled:
                    self.tool_fbo_rect = Rectangle(pos=self.fbo_rect.pos, size=self.tool_fbo.texture.size,
                                                   texture=self.tool_fbo.texture)
        self.fbo_update_pos()
        self.fbo.draw()
        self.canvas.ask_update()

    def fbo_create_on_canvas(self, size=None, pos=(0, 0)):
        self.canvas.clear()
        if size is None:
            size = self.fbo_size
        else:
            self.fbo_size = size
        self.fbo_create(size)
        with self.canvas:
            Color(1, 1, 1, 1)
            self.fbo_rect = Rectangle(texture=self.fbo.texture, pos=pos, size=self.fbo.texture.size)
            self.tool_fbo_rect = Rectangle(texture=self.tool_fbo.texture, pos=pos, size=self.tool_fbo.texture.size)
        self.fbo.draw()
        self.canvas.ask_update()


    def fbo_clear(self):
        self.fbo.bind()
        self.fbo.clear()
        self.fbo.clear_color = self.fbo_clear_color
        self.fbo.clear_buffer()
        self.fbo.release()
        self.fbo.draw()

    def fbo_update_pos(self):
        x = self.app.aPaintLayout.size[0] / self.scale / 2 - self.fbo.size[0] / 2
        y = self.app.aPaintLayout.size[1] / self.scale / 2 - self.fbo.size[1] / 2
        self.fbo_rect.pos = (x, y)
        self.tool_fbo_rect.pos = (x, y)
        if self.bg_rect:
            self.bg_rect.pos = (x, y)
        if self.app.layer_ribbon:
            for lb in layer.LayerBox.boxlist:
                if lb.layer.rect:
                    lb.layer.rect.pos = self.fbo_rect.pos

    def fbo_move_by_offset(self, offset):
        if self.bg_rect:
            self.bg_rect.pos = self.bg_rect.pos[0] + offset[0], self.bg_rect.pos[1] + offset[1]
            self.fbo_rect.pos = self.bg_rect.pos
            self.tool_fbo_rect.pos = self.bg_rect.pos
        if self.app.layer_ribbon:
            for lb in layer.LayerBox.boxlist:
                if lb.layer.rect:
                    lb.layer.rect.pos = self.fbo_rect.pos
        # self.ox, self.oy = self.bg_rect.pos
    #
    def fbo_render(self, touch, width):
        self.fbo.bind()
        if touch and touch.ud.has_key('line'):
            with self.fbo:
                self.fbo.add(self.app.aColor)
                d = width
                self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0],
                                   (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1])
                touch.ud['line'].points += self.cursor_pos
        self.fbo.release()
        self.fbo.draw()
        self.canvas.ask_update()

    def fbo_get_texture(self):
        return self.fbo.texture

    def fbo_get_pixel_color(self, touch, format='1'):
        self.fbo.bind()
        x = touch.x / self.scale - self.fbo_rect.pos[0]
        y = touch.y / self.scale - self.fbo_rect.pos[1]
        data = glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE)
        self.fbo.release()
        if format == '1':
            c = [ord(a) / 255.0 for a in data]
        else:
            c = [ord(a) for a in data]
        return c

    def fbo_fill_region(self, touch):
        x = int(touch.x / self.scale - self.fbo_rect.pos[0])
        y = int(touch.y / self.scale - self.fbo_rect.pos[1])
        improc.fillimage(self.fbo, (x, y), [int(255 * c) for c in self.app.aColor.rgba])
        self.canvas.ask_update()

    def fbo_replace_color(self, touch, width):
        cx = int(touch.x / self.scale - self.fbo_rect.pos[0])
        cy = int(touch.y / self.scale - self.fbo_rect.pos[1])
        if self.px is None:
            self.px = cx
        if self.py is None:
            self.py = cy
        if (cx - self.px) > 0:
            tg_alpha = float((cy - self.py)) / (cx - self.px)
            step = int(math.copysign(1, tg_alpha))
            if abs(cx - self.px) > abs(cy - self.py):
                coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(self.px), int(cx))]
            else:
                coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(self.py), int(cy), step)]
        elif (cx - self.px) < 0:
            tg_alpha = float((cy - self.py)) / (cx - self.px)
            step = int(math.copysign(1, tg_alpha))
            if abs(cx - self.px) > abs(cy - self.py):
                coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(cx), int(self.px))]
            else:
                coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(cy), int(self.py), step)]
        elif (cx - self.px) == 0:
            if (cy - self.py) > 0:
                coords = [(cx, y) for y in xrange(int(self.py), int(cy))]
            elif (cy - self.py) < 0:
                coords = [(cx, y) for y in xrange(int(cy), int(self.py))]
            else:
                coords = [(cx, cy), ]
        self.fbo.bind()
        for (x, y) in coords:
            improc.texture_replace_color(tex=self.fbo.texture, pos=(x, y), color=0, size=(width, width))
        self.fbo.release()
        self.fbo.clear()
        self.fbo.draw()
        self.canvas.ask_update()
        self.px = cx
        self.py = cy

    def pos_to_widget(self, touch):
        return self.to_widget(touch.x, touch.y)

    def scale_canvas(self, zoom):
        with self.canvas.before:
            PushMatrix()
            self.scale *= zoom
            context_instructions.Scale(zoom)
        with self.canvas.after:
            PopMatrix()
        self.fbo_update_pos()

    def on_scale(self, instance, scale):
        ToolBehavior.scale()

    def scale_pos(self, pos):
        return [pos[0] / self.scale - self.fbo_rect.pos[0],
                pos[1] / self.scale - self.fbo_rect.pos[1]]

    def scaled_pos(self):
        return [self.fbo_rect.pos[0] * self.scale,
                self.fbo_rect.pos[1] * self.scale]

    def scaled_size(self):
        return [self.fbo_rect.texture.size[0] * self.scale,
                self.fbo_rect.texture.size[1] * self.scale]

    def add_touch(self, touch):
        if touch and len(self.touches) < 2:
            self.touches.append(touch)
        if len(self.touches) >= 2:
            self.touch_dist = self.touches[0].distance(self.touches[1])
            self.touch_dist_const = self.touch_dist
            self.first_touch = self.touches[0]

    def double_touch(self):
        if len(self.touches) > 1:
            return True

    # def double_touch_distance(self):
    #     return Vector(self.touches[0].pos).distance(self.touches[1].pos)

    def touch_responce(self):
        result = False
        if len(self.touches) >= 2:
            pos1 = self.pos_to_widget(self.touches[0])
            pos2 = self.touches[1].pos
            dist = distance(pos1, pos2)
            if dist > self.touch_dist + 10:
                self.touch_dist = dist
                result = 2
            elif dist <= self.touch_dist - 10:
                self.touch_dist = dist
                result = 1
            if abs(self.touch_dist_const - dist) < 10:
                result = 3
            return result
        return False

    def on_touch_down(self, touch):
        self.tool_buffer.on_touch_down(touch)

        if self.collide_point(*touch.pos):
            if self.app.config.getint('toolbars', 'toolbar_autohide'):
                self.app.toolbar.animate_hide()
            if self.app.config.getint('toolbars', 'palette_autohide'):
                self.app.palette.animate_hide()
            if self.app.config.getint('toolbars', 'layer_ribbon_autohide'):
                self.app.layer_ribbon.animate_hide()

        if not self.collide_point(*touch.pos):
            if self.app.active_tool == TOOL_LINE:
                self.tool_line._render_and_reset_state(self.fbo, self.tool_fbo)
                self.fbo.draw()
                self.canvas.ask_update()

            return False

        touch.grab(self)

        self.add_touch(touch)

        if len(self.touches) == 1:
            self.active_layer_backup_texture()

        if self.double_touch():
            self.active_layer_set_last_backup_texture()
            return

        if not self.app.layer_ribbon.get_active_layer().visible:
            dialog.PopupMessage("Notification", "The current layer is hidden, make it visible for edit")
            return
        if self.app.layer_ribbon.get_active_layer().texture_locked:
            dialog.PopupMessage("Notification", "The current layer is locked, make it unlock for edit")
            return

        if self.app.active_tool == TOOL_PENCIL1:
            self.fbo.bind()
            if touch:
                with self.fbo:
                    self.fbo.add(self.app.aColor)
                    d = 1.
                    self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0],
                                       (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1])
                    Ellipse(pos=self.cursor_pos, size=(d, d))
                    touch.ud['line'] = Line(points=self.cursor_pos, width=d)
            self.fbo.release()
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_PENCIL2:
            self.fbo.bind()
            if touch:
                with self.fbo:
                    self.fbo.add(self.app.aColor)
                    d = 2.1
                    self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0],
                                       (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1])
                    Ellipse(pos=self.cursor_pos, size=(d, d))
                    touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2.0)
            self.fbo.release()
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_PENCIL3:
            self.fbo.bind()
            if touch:
                with self.fbo:
                    self.fbo.add(self.app.aColor)
                    d = 3.
                    self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0],
                                       (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1])
                    Ellipse(pos=self.cursor_pos, size=(d, d))
                    touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2)
            self.fbo.release()
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_PICKER:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    c = self.fbo_get_pixel_color(touch)
                    self.app.aColor = Color(c[0], c[1], c[2], c[3])
                    self.app.toolbar.tools_select(self.app.prev_tool)
        elif self.app.active_tool == TOOL_FILL:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_fill_region(touch)
        elif self.app.active_tool == TOOL_ERASE1:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=1)
        elif self.app.active_tool == TOOL_ERASE2:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=2)
        elif self.app.active_tool == TOOL_ERASE3:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=3)
        elif self.app.active_tool == TOOL_SELECT:
            if touch:
                if not self.tool_buffer.enabled:
                    self.tool_select.on_touch_down(touch, self.fbo, self.tool_fbo)
                else:
                    pass
        elif self.app.active_tool == TOOL_LINE:
            if touch:
                self.tool_line.on_touch_down(touch, self.fbo, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_RECT:
            if touch:
                self.tool_rect.on_touch_down(touch, self.fbo, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_ELLIPSE:
            if touch:
                self.tool_ellipse.on_touch_down(touch, self.fbo, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_MOVE:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.move_image = True
                    self.ox, self.oy = touch.pos
        return True

    def on_touch_move(self, touch):
        result = self.touch_responce()
        if result == 2:
            self.scale_canvas(1.02)
            return
        elif result == 1:
            self.scale_canvas(0.98)
            return
        elif result == 3:
            dist = self.touches[0].distance(self.first_touch)
            self.fbo_move_by_offset((dist / self.scale, dist / self.scale))

        if self.app.active_tool == TOOL_PENCIL1:
            self.fbo_render(touch, width=1.)
        elif self.app.active_tool == TOOL_PENCIL2:
            self.fbo_render(touch, width=2.)
        elif self.app.active_tool == TOOL_PENCIL3:
            self.fbo_render(touch, width=3.)
        elif self.app.active_tool == TOOL_PICKER:
            c = self.fbo_get_pixel_color(touch)
            self.app.aColor = Color(c[0], c[1], c[2])
        elif self.app.active_tool == TOOL_ERASE1:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=1)
        elif self.app.active_tool == TOOL_ERASE2:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=2)
        elif self.app.active_tool == TOOL_ERASE3:
            if touch:
                if self.collide_point(touch.x, touch.y):
                    self.fbo_replace_color(touch, width=3)
        elif self.app.active_tool == TOOL_SELECT:
            if touch:
                if not self.tool_buffer.enabled:
                    self.tool_select.on_touch_move(touch, self.tool_fbo)
                    self.fbo.draw()
                    self.canvas.ask_update()
                else:
                    pass

        elif self.app.active_tool == TOOL_LINE:
            if touch:
                self.tool_line.on_touch_move(touch, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_RECT:
            if touch:
                self.tool_rect.on_touch_move(touch, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_ELLIPSE:
            if touch:
                self.tool_ellipse.on_touch_move(touch, self.tool_fbo)
            self.fbo.draw()
            self.canvas.ask_update()
        elif self.app.active_tool == TOOL_MOVE:
            if self.move_image:
                self.fbo_move_by_offset((touch.dx / self.scale, touch.dy / self.scale))
        self.tool_buffer.on_touch_move(touch, self.fbo)

    def on_touch_up(self, touch):
        self.tool_buffer.on_touch_up(touch)
        if touch.grab_current is not self:
            return False
        if not self.collide_point(*touch.pos):
            return False
        touch.ungrab(self)

        if self.double_touch():
            _not_add_too_undo = True
        else:
            _not_add_too_undo = False

        if touch:
            try:
                self.touches.remove(touch)
            except:
                pass
            if self.app.active_tool == TOOL_SELECT:
                if touch:
                    self.tool_select.on_touch_up(touch)
                self.fbo.draw()
                self.canvas.ask_update()
            elif self.app.active_tool == TOOL_LINE:
                if touch:
                    self.tool_line.on_touch_up(touch)
                self.fbo.draw()
                self.canvas.ask_update()
            elif self.app.active_tool == TOOL_RECT:
                if touch:
                    self.tool_rect.on_touch_up(touch)
                self.fbo.draw()
                self.canvas.ask_update()
            elif self.app.active_tool == TOOL_ELLIPSE:
                if touch:
                    self.tool_ellipse.on_touch_up(touch)
                self.fbo.draw()
                self.canvas.ask_update()
            elif self.app.active_tool == TOOL_MOVE:
                if touch:
                    self.move_image = False
            elif self.app.active_tool == TOOL_ERASE1 or self.app.active_tool == TOOL_ERASE2 or self.app.active_tool == TOOL_ERASE3:
                if touch:
                    self.px = None
                    self.py = None
            if self.app.active_tool == TOOL_PENCIL1 or self.app.active_tool == TOOL_ERASE1 \
                    or self.app.active_tool == TOOL_PENCIL2 or self.app.active_tool == TOOL_ERASE2 \
                    or self.app.active_tool == TOOL_PENCIL3 or self.app.active_tool == TOOL_ERASE3 \
                    or self.app.active_tool == TOOL_FILL:
                rect = self.app.layer_ribbon.get_active_layer().rect
                pos = rect.pos[0] * self.scale, rect.pos[1] * self.scale
                size = rect.size[0] * self.scale, rect.size[1] * self.scale
                if not _not_add_too_undo:
                    if pos[0] <= touch.x <= pos[0] + size[0] and pos[1] <= touch.y <= pos[1] + size[1]:
                        self.add_undo_stack()
        return True

    def add_redo_stack(self):
        pass

    def add_undo_stack(self):
        _active_layer = self.app.layer_ribbon.get_active_layer()
        _active_layer.backup_texture()
        self.layer_undo_stack = self.layer_undo_stack[:self.undo_layer_index + 1]
        self.layer_undo_stack.append(_active_layer)
        self.undo_layer_index = len(self.layer_undo_stack) - 1

    def do_undo(self, *args):
        if self.layer_undo_stack:
            if self.undo_layer_index > 0:
                _layer = self.layer_undo_stack[self.undo_layer_index]
                _layer.texture_from_backup(direction=-1)
                _active_layer = self.app.layer_ribbon.get_active_layer()
                if _layer is _active_layer:
                    self.fbo_create(_active_layer.texture.size, _active_layer.texture)
                self.undo_layer_index -= 1
                self.canvas_put_drawarea()
            self.fbo_update_pos()

    def active_layer_backup_texture(self):
        active_layer = self.app.layer_ribbon.get_active_layer()
        self.active_layer_last_texture = improc.texture_copy(active_layer.texture)

    def active_layer_set_last_backup_texture(self):
        active_layer = self.app.layer_ribbon.get_active_layer()
        # texture = active_layer.textures_array[-1]
        active_layer.replace_texture(self.active_layer_last_texture)

        self.fbo_create(active_layer.texture.size, active_layer.texture)

        self.canvas_put_drawarea()
        self.fbo_update_pos()
        self.canvas.ask_update()

    def do_redo(self, *args):
        if self.layer_undo_stack:
            if self.undo_layer_index < len(self.layer_undo_stack) - 1:
                self.undo_layer_index += 1
                _layer = self.layer_undo_stack[self.undo_layer_index]
                _layer.texture_from_backup(direction=1)
                _active_layer = self.app.layer_ribbon.get_active_layer()
                if _layer is _active_layer:
                    self.fbo_create(_active_layer.texture.size, _active_layer.texture)
                self.canvas_put_drawarea()
            self.fbo_update_pos()
Esempio n. 8
0
class ObjectRenderer(Widget):
    scene = StringProperty('')
    obj_id = StringProperty('')
    obj_translation = ListProperty([0, 0, 0])
    obj_rotation = ListProperty([0, 0, 0])
    obj_scale = NumericProperty(1)
    obj_texture = StringProperty('')
    texture = ObjectProperty(None, allownone=True)
    cam_translation = ListProperty([0, 0, 0])
    cam_rotation = ListProperty([0, 0, 0])
    display_all = BooleanProperty(False)
    light_sources = DictProperty()
    ambiant = NumericProperty(.5)
    diffuse = NumericProperty(.5)
    specular = NumericProperty(.5)
    mode = StringProperty('triangles')

    def __init__(self, **kwargs):
        self.canvas = Canvas()
        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(
            join(dirname(__file__), 'simple.glsl'))
        super(ObjectRenderer, self).__init__(**kwargs)

    def on_obj_rotation(self, *args):
        self.obj_rot_x.angle = self.obj_rotation[0]
        self.obj_rot_y.angle = self.obj_rotation[1]
        self.obj_rot_z.angle = self.obj_rotation[2]

    def on_cam_rotation(self, *args):
        self.cam_rot_x.angle = self.cam_rotation[0]
        self.cam_rot_y.angle = self.cam_rotation[1]
        self.cam_rot_z.angle = self.cam_rotation[2]

    def on_obj_translation(self, *args):
        self.obj_translate.xyz = self.cam_translation

    def on_cam_translation(self, *args):
        self.cam_translate.xyz = self.cam_translation

    def on_obj_scale(self, *args):
        self.scale.xyz = [
            self.obj_scale,
        ] * 3

    def on_display_all(self, *args):
        self.setup_canvas()

    def on_light_sources(self, *args):
        self.fbo['light_sources'] = [
            ls[:] for ls in self.light_sources.values()
        ]
        self.fbo['nb_lights'] = len(self.light_sources)

    def on_ambiant(self, *args):
        self.fbo['ambiant'] = self.ambiant

    def on_diffuse(self, *args):
        self.fbo['diffuse'] = self.diffuse

    def on_specular(self, *args):
        self.fbo['specular'] = self.specular

    def on_mode(self, *args):
        self.setup_canvas()

    def setup_canvas(self, *args):
        if not (self.scene and self.obj_id or self.display_all):
            return

        print 'setting up the scene'
        with self.fbo:
            self.fbo['ambiant'] = self.ambiant
            self.fbo['diffuse'] = self.diffuse
            self.fbo['specular'] = self.specular
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            self.setup_scene()
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)

    def on_scene(self, instance, value):
        print "loading scene %s" % value
        self._scene = ObjFileLoader(resource_find(value))
        self.setup_canvas()

    def on_obj_id(self, *args):
        self.setup_canvas()

    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):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def update_glsl(self, *args):
        asp = self.width / max(float(self.height), 1)
        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()
        self.cam_translate = Translate(self.cam_translation)
        # Rotate(0, 1, 0, 0)
        self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0)
        self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0)
        self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1)
        self.scale = Scale(self.obj_scale)
        UpdateNormalMatrix()
        if self.display_all:
            for i in self._scene.objects:
                self.draw_object(i)
        else:
            self.draw_object(self.obj_id)
        PopMatrix()

    def draw_object(self, obj_id):
        m = self._scene.objects[obj_id]
        self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1)
        self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0)
        self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0)
        self.obj_translate = Translate(xyz=self.obj_translation)

        if len(m.indices) > 2**16:
            print '%s too big! %s indices' % (obj_id, len(m.indices))

        if m.texture:
            print "loading texture %s " % m.texture
            img = Image(
                source=resource_find(join(dirname(self.scene), m.texture)))
            texture = img.texture
            if texture:
                texture.wrap = 'repeat'
        else:
            texture = None

        vertex_lenght = sum(x[1] for x in m.vertex_format)
        if len(m.vertices) % vertex_lenght:
            print(('warning: vertices lenght (%s)'
                   'is not a multiple of vertex_format lenght(%s)') %
                  (len(m.vertices), vertex_lenght))
        Mesh(vertices=m.vertices,
             indices=m.indices,
             fmt=m.vertex_format,
             texture=texture,
             mode=self.mode)
Esempio n. 9
0
class Renderer(Widget):
    texture = ObjectProperty(None, allownone=True)

    def load(self, *l):
        self.button.disabled = True

        if os.path.isdir(meshdir):
            rep = meshdir
            self.fl = FileChooserListView(path=rep,
                                          rootpath=rep,
                                          filters=["*.mesh.ascii"],
                                          dirselect=False,
                                          size=(400, 400),
                                          center_x=250,
                                          center_y=250)
        else:
            rep = os.getcwd()
            self.fl = FileChooserListView(path=rep,
                                          filters=["*.mesh.ascii"],
                                          dirselect=False,
                                          size=(400, 400),
                                          center_x=250,
                                          center_y=250)
        '''if platform == 'android':
            rep = "."
        else:
            rep = "../../Mesh"'''

        self.fl.bind(selection=self.on_selected)
        super(Renderer, self).add_widget(self.fl)

    def on_selected(self, filechooser, selection):
        self.button.disabled = False

        print 'load', selection
        super(Renderer, self).remove_widget(self.fl)

        scale = 3
        self.fbo.remove_group('truc')

        self.scene = MeshAsciiLoader(selection[0], scale)

        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)

    def change_shader(self, *l):
        print 'change_shader'
        if self.shader == 0:
            self.fbo.shader.source = resource_find('simple.glsl')
            self.shader = 1
        else:
            #self.fbo.shader.source = resource_find('flat.glsl')
            self.fbo.shader.source = resource_find('normalmap.glsl')
            self.shader = 0

    def __init__(self, **kwargs):
        self.model = 0
        self.shader = 0
        self.canvas = Canvas()
        #self.scene = ObjFileLoader(resource_find("testnurbs.obj"))

        Logger.debug('******************************************************')
        scale = 3
        #dir = "Duke Nukem Forever_Dr_Valencia" # error index out of range
        #dir = "Duke Nukem Forever_Kitty Pussoix"
        dir = "Duke_Nukem_by_Ventrue"
        #dir = "DOA5U_Rachel_Nurse/Model" #pb uv

        if not os.path.isdir(meshdir):
            self.scene = MeshAsciiLoader(
                resource_find(dir + "/Generic_Item.mesh.ascii"), scale)
        else:
            self.scene = MeshAsciiLoader(
                resource_find(meshdir + dir + "/Generic_Item.mesh.ascii"),
                scale)

        #scale = .03
        #self.texturename = 'Batman_Rabbit_Head_Posed/Batman_V3_Body_D.PNG'
        #self.scene = PSKFileLoader(resource_find("Batman_Rabbit_Head_Posed/Batman_Rabbit_Head_Posed.psk"), scale)
        #self.texturename = 'Gray/Gray_C1.tga'
        #self.scene = PSKFileLoader(resource_find("Gray/Mike_TPP.psk"), scale) #too many indices, good for split test
        #self.texturename = 'CV_Talia/Talia_Body_D.tga'
        #self.texturename = 'CV_Talia/Talia_Legs_D.tga')
        #self.scene = PSKFileLoader(resource_find("CV_Talia/Talia_posed.psk"), scale) #too many indices, good for split test
        Logger.debug('******************************************************')

        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.fbo.shader.source = resource_find('normalmap.glsl')

        super(Renderer, self).__init__(**kwargs)

        self.fbo['texture1'] = 1
        self.fbo['toggletexture'] = 1

        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 = []

        self.button = Button(text='load')
        self.button.bind(on_release=self.load)
        super(Renderer, self).add_widget(self.button)

        button1 = Button(text='shader', center_x=150)
        button1.bind(on_release=self.change_shader)
        super(Renderer, self).add_widget(button1)

    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, 500, 1)
        self.fbo['projection_mat'] = proj
        self.fbo['diffuse_light'] = (1.0, 0.0, 0.0)
        self.fbo['ambient_light'] = (0.1, 0.1, 0.1)
        self.fbo['glLightSource0_position'] = (1.0, 1.0, 1.0, 0.0)
        self.fbo['glLightSource0_spotCutoff'] = 360
        self.fbo['glLightModel_ambient'] = (0.2, 0.2, 0.2, 1.0)
        self.fbo['glLightSource0_diffuse'] = (0.7, 0.7, 0.7, 1.0)
        self.fbo['glLightSource0_specular'] = (.1, .1, .1, 1.0)
        self.fbo['glFrontMaterial_specular'] = (.10, .10, .10, 1.0)
        self.fbo['glFrontMaterial_shininess'] = 0.1

    def setup_scene(self):
        Color(.5, .5, .5, 0)

        PushMatrix()
        Translate(0, -3, -5)
        # This Kivy native Rotation is used just for
        # enabling rotation scene like trackball
        self.rotx = Rotate(0, 1, 0, 0)
        # here just rotate scene for best view
        self.roty = Rotate(180, 0, 1, 0)
        self.scale = Scale(1)

        UpdateNormalMatrix()

        self.draw_elements()

        PopMatrix()

    def draw_elements(self):
        #Draw separately all meshes on the scene
        def _draw_element(m, texture='', texture1=''):
            #bind the texture BEFORE the draw (Mesh)
            if texture1:
                # here, we are binding a custom texture at index 1
                # this will be used as texture1 in shader.
                tex1 = Image(texture1).texture
                tex1.wrap = 'repeat'  #enable of uv support >1 or <0
                BindTexture(texture=tex1, index=1)
            #clear the texture if none
            else:
                BindTexture(source="", index=1)

            mesh = Mesh(
                vertices=m.vertices,
                indices=m.indices,
                fmt=m.vertex_format,
                mode='triangles',
                group='truc',
            )

            if texture:
                try:
                    texture = Image(texture).texture
                    texture.wrap = 'repeat'  #enable of uv support >1 or <0
                    mesh.texture = texture
                except:  #no texture if not found or not supported
                    pass

        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],
            )

        for meshid in range(0, len(self.scene.objects)):
            # Draw each element
            mesh = self.scene.objects[meshid]
            #_set_color(0.7, 0.7, 0., id_color=(255, 255, 0))
            if (mesh.diffuse != ""):
                _draw_element(mesh, mesh.diffuse, mesh.normal)
                #_draw_element(mesh, mesh.diffuse)
                #_draw_element(mesh, mesh.normal)
            else:
                _draw_element(mesh, self.texturename)

    def update_scene(self, *largs):
        pass

    # ============= 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)
        return super(Renderer, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        touch.ungrab(self)
        self._touches.remove(touch)
        return super(Renderer, self).on_touch_up(touch)

    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)
Esempio n. 10
0
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)
Esempio n. 11
0
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)
Esempio n. 12
0
class Renderer(Widget):

    texture = ObjectProperty(None, allownone=True)

    def __init__(self, **kwargs):
        self.canvas = Canvas()
        self.scene = ObjFileLoader(resource_find("brain.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=(0, -150))
        self.fbo.shader.source = resource_find('simple.glsl')

        super(Renderer, self).__init__(**kwargs)

        with self.fbo:
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            self.setup_scene()
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)

    def on_size(self, instance, value):
        self.fbo.size = value
        self.viewport.texture = self.fbo.texture
        self.viewport.size = value
        self.update_glsl()

    def setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

    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, -8)
        # This Kivy native Rotation is used just for
        # enabling rotation scene like trackball
        self.rotx = Rotate(0, 1, 0, 0)
        self.roty = Rotate(-180, 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=(.1, .1, .1),
                Tr=1.,
                Ns=1.,
                intensity=1.,
                id_color=[i / 255. for i in id_color],
            )

        # Draw sphere in the center
        brain = self.scene.objects['Brain']
        _set_color(.659, .439, .361, id_color=(255, 255, 255))
        _draw_element(brain)

        brain2 = self.scene.objects['Brain2']
        _set_color(.659, .439, .361, id_color=(255, 255, 255))
        _draw_element(brain2)
Esempio n. 13
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