예제 #1
0
class PointRenderer(Widget):
    def __init__(self, **kwargs):
        self.canvas = RenderContext(use_parent_projection=True)
        self.canvas.shader.source = 'pointshader.glsl'
        glEnable(0x8642)  #GL_VERTEX_PROGRAM_POINT_SIZE
        glEnable(0x8861)  #GL_POINT_SPRITE
        self.mesh = None
        super(PointRenderer, self).__init__(**kwargs)
        self.draw_mesh_points(60)
        Clock.schedule_interval(self.test_mesh_remove, 1. / 60.)

    def test_mesh_remove(self, dt):

        r = random()
        if r > .5:
            self.canvas.remove(self.mesh)
            self.mesh = None
        self.draw_mesh_points(60)

    def draw_mesh_points(self, number):
        star_list = []
        w, h = self.size
        sa = star_list.append
        for number in range(number):
            rand_x = random() * w
            rand_y = random() * h
            size = 29.0
            rotation = random() * 360.0
            sa((rand_x, rand_y, size, rotation))
        self.draw_mesh(star_list)

    def draw_mesh(self, star_list):
        star_tex = Image('star1.png').texture
        vertex_format = [
            (b'vPosition', 2, 'float'),
            (b'vSize', 1, 'float'),
            (b'vRotation', 1, 'float'),
        ]
        indices = []
        ia = indices.append
        for star_number in range(len(star_list)):
            ia(star_number)
        vertices = []
        e = vertices.extend
        for star in star_list:
            e([star[0], star[1], star[2], star[3]])
        if self.mesh == None:
            with self.canvas:
                PushMatrix()
                self.mesh = Mesh(indices=indices,
                                 vertices=vertices,
                                 fmt=vertex_format,
                                 mode='points',
                                 texture=star_tex)
                PopMatrix()
        else:
            self.mesh.indices = indices
            self.mesh.vertices = vertices
예제 #2
0
파일: effectwidget.py 프로젝트: 9miao/kivy
class EffectWidget(RelativeLayout):
    '''
    Widget with the ability to apply a series of graphical effects to
    its children. See module documentation for full information on
    setting effects and creating your own.
    '''

    background_color = ListProperty((0, 0, 0, 1))
    '''This defines the background color to be used for the fbo in the
    EffectWidget.

    :attr:`background_color` is a :class:`ListProperty` defaults to
    (0, 0, 0, 1)
    '''

    texture = ObjectProperty(None)
    '''The output texture of our final :class:`~kivy.graphics.Fbo` after
    all effects have been applied.

    texture is an :class:`~kivy.properties.ObjectProperty` and defaults
    to None.
    '''

    effects = ListProperty([])
    '''List of all the effects to be applied. These should all be
    instances of :class:`EffectBase`.

    effects is a :class:`ListProperty` and defaults to [].
    '''

    fbo_list = ListProperty([])
    '''(internal) list of all the fbos that are being used to apply
    the effects.

    fbo_list is a :class:`ListProperty` and defaults to [].
    '''

    _bound_effects = ListProperty([])
    '''(internal) list of effect classes that have been given an fbo to
    manage. This is necessary so that the fbo can be removed it the
    effect is no longer in use.

    _bound_effects is a :class:`ListProperty` and defaults to [].
    '''

    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
        with self.fbo:
            ClearColor(0, 0, 0, 0)
            ClearBuffers()
            self._background_color = Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

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

        Clock.schedule_interval(self._update_glsl, 0)

        self.bind(size=self.refresh_fbo_setup,
                  effects=self.refresh_fbo_setup,
                  background_color=self._refresh_background_color)

        self.refresh_fbo_setup()
        self._refresh_background_color()  # In case thi was changed in kwargs

    def _refresh_background_color(self, *args):
        self._background_color.rgba = self.background_color

    def _update_glsl(self, *largs):
        '''(internal) Passes new time and resolution uniform
        variables to the shader.
        '''
        time = Clock.get_boottime()
        resolution = [float(size) for size in self.size]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution

    def refresh_fbo_setup(self, *args):
        '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo`
        per effect, and makes sure all sizes etc. are correct and
        consistent.
        '''
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=self.size)
            with new_fbo:
                ClearColor(0, 0, 0, 0)
                ClearBuffers()
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(size=self.size)

                new_fbo.texture_rectangle.size = self.size
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Remove fbos from unused effects
        for effect in self._bound_effects:
            if effect not in self.effects:
                effect.fbo = None
        self._bound_effects = self.effects

        # Do resizing etc.
        self.fbo.size = self.size
        self.fbo_rectangle.size = self.size
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = self.size
            self.fbo_list[i].texture_rectangle.size = self.size

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        # Build effect shaders
        for effect, fbo in zip(self.effects, self.fbo_list):
            effect.fbo = fbo

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
예제 #3
0
class EffectWidget(RelativeLayout):
    '''
    Widget with the ability to apply a series of graphical effects to
    its children. See the module documentation for more information on
    setting effects and creating your own.
    '''

    background_color = ListProperty((0, 0, 0, 1))
    '''This defines the background color to be used for the fbo in the
    EffectWidget.

    :attr:`background_color` is a :class:`ListProperty` defaults to
    (0, 0, 0, 1)
    '''

    texture = ObjectProperty(None)
    '''The output texture of the final :class:`~kivy.graphics.Fbo` after
    all effects have been applied.

    texture is an :class:`~kivy.properties.ObjectProperty` and defaults
    to None.
    '''

    effects = ListProperty([])
    '''List of all the effects to be applied. These should all be
    instances or subclasses of :class:`EffectBase`.

    effects is a :class:`ListProperty` and defaults to [].
    '''

    fbo_list = ListProperty([])
    '''(internal) List of all the fbos that are being used to apply
    the effects.

    fbo_list is a :class:`ListProperty` and defaults to [].
    '''

    _bound_effects = ListProperty([])
    '''(internal) List of effect classes that have been given an fbo to
    manage. This is necessary so that the fbo can be removed if the
    effect is no longer in use.

    _bound_effects is a :class:`ListProperty` and defaults to [].
    '''
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
        with self.fbo:
            ClearColor(0, 0, 0, 0)
            ClearBuffers()
            self._background_color = Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

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

        Clock.schedule_interval(self._update_glsl, 0)

        fbind = self.fbind
        fbo_setup = self.refresh_fbo_setup
        fbind('size', fbo_setup)
        fbind('effects', fbo_setup)
        fbind('background_color', self._refresh_background_color)

        self.refresh_fbo_setup()
        self._refresh_background_color()  # In case thi was changed in kwargs

    def _refresh_background_color(self, *args):
        self._background_color.rgba = self.background_color

    def _update_glsl(self, *largs):
        '''(internal) Passes new time and resolution uniform
        variables to the shader.
        '''
        time = Clock.get_boottime()
        resolution = [float(size) for size in self.size]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution

    def refresh_fbo_setup(self, *args):
        '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo`
        per effect, and makes sure all sizes etc. are correct and
        consistent.
        '''
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=self.size)
            with new_fbo:
                ClearColor(0, 0, 0, 0)
                ClearBuffers()
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(size=self.size)

                new_fbo.texture_rectangle.size = self.size
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Remove fbos from unused effects
        for effect in self._bound_effects:
            if effect not in self.effects:
                effect.fbo = None
        self._bound_effects = self.effects

        # Do resizing etc.
        self.fbo.size = self.size
        self.fbo_rectangle.size = self.size
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = self.size
            self.fbo_list[i].texture_rectangle.size = self.size

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        # Build effect shaders
        for effect, fbo in zip(self.effects, self.fbo_list):
            effect.fbo = fbo

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
예제 #4
0
class EffectWidget(FloatLayout):

    fs = StringProperty(None)

    # Texture of the final Fbo
    texture = ObjectProperty(None)

    # Rectangle clearing Fbo
    fbo_rectangle = ObjectProperty(None)

    # List of effect strings
    effects = ListProperty([])

    # One extra Fbo for each effect
    fbo_list = ListProperty([])

    effect_mask = None
    motion_effect = None

    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()
        self.mask_effect = kwargs.get("mask_effect", None)
        self.motion_effect = kwargs.get("motion_effect", None)

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        self.size = C_SIZE
        with self.canvas:
            #self._viewport = Rectangle(size=(800,600), pos=self.pos)
            self.fbo = Fbo(size=C_SIZE,
                           with_depthbuffer=True,
                           compute_normal_mat=True,
                           clear_color=(0.3, 0.3, 0.7, 1))

        with self.fbo.before:
            #Rectangle(size=(800, 600))
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)

        with self.fbo:
            Color(0, 0, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)
            self.fbo_rectangle = Rectangle(size=C_SIZE)
            self._instructions = InstructionGroup()

        with self.fbo.after:
            PopMatrix()
            self.cbs = Callback(self.reset_gl_context)

        super(EffectWidget, self).__init__()
        self.size = C_SIZE

        Clock.schedule_interval(self.update_glsl, 0)

        self._instructions.add(Callback(self.setup_gl_context))

        self.refresh_fbo_setup()
        Clock.schedule_interval(self.update_fbos, 0)

    def on_pos(self, *args):
        self.fbo_translation.x = -self.x
        self.fbo_translation.y = -self.y

    def on_size(self, instance, value):
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        self.refresh_fbo_setup()

        #self._viewport.texture = self.fbo.texture
        #self._viewport.size = value

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

        #for fbo in self.fbo_list:
        #    fbo.clear_buffer()

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

    def update_glsl(self, *largs):
        time = Clock.get_boottime()
        resolution = [float(size) for size in C_SIZE]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        self.canvas['texture4'] = 4
        self.canvas['texture5'] = 5
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution
            fbo['texture4'] = 4
            fbo['texture5'] = 5

    def on_effects(self, *args):
        self.refresh_fbo_setup()

    def update_fbos(self, *args):
        for fbo in self.fbo_list:
            fbo.ask_update()

    def refresh_fbo_setup(self, *args):
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=C_SIZE)
            with new_fbo:
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(size=C_SIZE)

                new_fbo.texture_rectangle.size = C_SIZE
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Do resizing etc.
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = C_SIZE
            self.fbo_list[i].texture_rectangle.size = C_SIZE

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        for effect, fbo in zip(self.effects, self.fbo_list):
            fbo.set_fs(shader_header + shader_uniforms + effect +
                       shader_footer_effect)

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def on_fs(self, instance, value):
        # set the fragment shader to our source code
        shader = self.canvas.shader
        old_value = shader.fs
        shader.fs = value
        if not shader.success:
            shader.fs = old_value
            raise Exception('failed')

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        #self._instructions.add(widget.canvas)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
예제 #5
0
class EffectWidget(FloatLayout):

    fs = StringProperty(None)

    # Texture of the final Fbo
    texture = ObjectProperty(None)

    # Rectangle clearing Fbo
    fbo_rectangle = ObjectProperty(None)

    # List of effect strings
    effects = ListProperty([])

    # One extra Fbo for each effect
    fbo_list = ListProperty([])

    effect_mask = None
    motion_effect = None

    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()
        self.mask_effect = kwargs.get("mask_effect", None)
        self.motion_effect = kwargs.get("motion_effect", None)

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        self.size = C_SIZE
        with self.canvas:
            #self._viewport = Rectangle(size=(800,600), pos=self.pos)
            self.fbo = Fbo(size=C_SIZE, with_depthbuffer=True,  compute_normal_mat=True,
                           clear_color=(0.3, 0.3, 0.7, 1))

        with self.fbo.before:
            #Rectangle(size=(800, 600))
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)

        with self.fbo:
            Color(0, 0, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)
            self.fbo_rectangle = Rectangle(size=C_SIZE)
            self._instructions = InstructionGroup()

        with self.fbo.after:
            PopMatrix()
            self.cbs = Callback(self.reset_gl_context)


        super(EffectWidget, self).__init__(**kwargs)
        self.size = C_SIZE

        Clock.schedule_interval(self.update_glsl, 0)

        self._instructions.add(Callback(self.setup_gl_context))

        self.refresh_fbo_setup()
        Clock.schedule_interval(self.update_fbos, 0)

    def on_pos(self, *args):
        self.fbo_translation.x = -self.x
        self.fbo_translation.y = -self.y

    def on_size(self, instance, value):
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        self.refresh_fbo_setup()

        #self._viewport.texture = self.fbo.texture
        #self._viewport.size = value


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

        #for fbo in self.fbo_list:
        #    fbo.clear_buffer()

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

    def update_glsl(self, *largs):
        time = Clock.get_boottime()
        resolution = [float(size) for size in C_SIZE]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        self.canvas['texture4'] = 4
        self.canvas['texture5'] = 5
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution
            fbo['texture4'] = 4
            fbo['texture5'] = 5


    def on_effects(self, *args):
        self.refresh_fbo_setup()

    def update_fbos(self, *args):
        for fbo in self.fbo_list:
            fbo.ask_update()

    def refresh_fbo_setup(self, *args):
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=C_SIZE)
            with new_fbo:
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(
                    size=C_SIZE)

                new_fbo.texture_rectangle.size = C_SIZE
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Do resizing etc.
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = C_SIZE
            self.fbo_list[i].texture_rectangle.size = C_SIZE

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        for effect, fbo in zip(self.effects, self.fbo_list):
            fbo.set_fs(shader_header + shader_uniforms + effect +
                       shader_footer_effect)

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def on_fs(self, instance, value):
        # set the fragment shader to our source code
        shader = self.canvas.shader
        old_value = shader.fs
        shader.fs = value
        if not shader.success:
            shader.fs = old_value
            raise Exception('failed')

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        #self._instructions.add(widget.canvas)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
예제 #6
0
class PointRenderer(Widget):

    def __init__(self, **kwargs):
        self.canvas = RenderContext(use_parent_projection=True)
        self.canvas.shader.source = 'pointshader.glsl'
        glEnable(0x8642) #GL_VERTEX_PROGRAM_POINT_SIZE
        glEnable(0x8861) #GL_POINT_SPRITE
        self.mesh = None
        super(PointRenderer, self).__init__(**kwargs) 
        self.draw_mesh_points(60)
        Clock.schedule_interval(self.test_mesh_remove, 1./60.)

    def test_mesh_remove(self, dt):
        
        r = random()
        if r > .5:
            self.canvas.remove(self.mesh)
            self.mesh = None
        self.draw_mesh_points(60)


    def draw_mesh_points(self, number):
        star_list = []
        w, h = self.size
        sa = star_list.append
        for number in xrange(number):
            rand_x = random()*w
            rand_y = random()*h
            size = 29.0
            rotation = random()*360.0
            sa((rand_x, rand_y, size, rotation))
        self.draw_mesh(star_list)


    def draw_mesh(self, star_list):
        star_tex = Image('star1.png').texture
        vertex_format = [
            ('vPosition', 2, 'float'),
            ('vSize', 1, 'float'),
            ('vRotation', 1, 'float'),
            ]
        indices = []
        ia = indices.append
        for star_number in range(len(star_list)):
            ia(star_number)
        vertices = []
        e = vertices.extend
        for star in star_list:
            e([
                star[0], star[1], star[2], star[3]
                ])
        if self.mesh == None:
            with self.canvas:
                PushMatrix()
                self.mesh = Mesh(
                    indices=indices,
                    vertices=vertices,
                    fmt=vertex_format,
                    mode='points',
                    texture=star_tex)
                PopMatrix()
        else:
            self.mesh.indices = indices
            self.mesh.vertices = vertices
예제 #7
0
class PointRenderer(Widget):
    def __init__(self, **kwargs):
        self.this_op = None
        self.units_per_meter = 16.0
        self.gravity = 9.8
        self.fps = 60.0
        self.vertex_format = [
            (b'vPosition', 3, 'float'),
            (b'vSize', 1, 'float'),
            (b'vRotation', 1, 'float'),
            (b'vVelocity', 3, 'float'),
        ]
        self.ROTATION_I = 4  # must match index of vRotation above
        self.VELOCITY_I = 5  # must match index of vVelocity above
        self.vertex_depth = 0
        for element in self.vertex_format:
            self.vertex_depth += element[1]
        self.star_list = []
        self.canvas = RenderContext(use_parent_projection=True)
        self.canvas.shader.source = 'pointshader3d.glsl'
        glEnable(0x8642)  #GL_VERTEX_PROGRAM_POINT_SIZE
        glEnable(0x8861)  #GL_POINT_SPRITE
        self.mesh = None
        super(PointRenderer, self).__init__(**kwargs)
        self.canvas["camera_eyespace_z"] = self.width / 2.0
        self.canvas["max_particle_size"] = self.width
        self.draw_mesh_points(60)
        #Clock.schedule_interval(self.test_mesh_remove, 1./60.)
        Clock.schedule_interval(self.test_mesh_move, 1. / self.fps)

    def test_mesh_move(self, dt):
        this_star_list = self.star_list
        offset = 0
        #sl_len = len(this_star_list)
        #vertex_count = int(sl_len/self.vertex_depth)
        #v_i = 0
        v_len = len(self.this_op.vertices)
        while offset < v_len:
            if self.this_op.vertices[offset + 1] > 0.0:
                self.this_op.vertices[offset] += self.this_op.vertices[
                    offset + self.VELOCITY_I]
                self.this_op.vertices[offset + 1] += self.this_op.vertices[
                    offset + self.VELOCITY_I + 1]  # +1 for y
                self.this_op.vertices[offset + 2] += self.this_op.vertices[
                    offset + self.VELOCITY_I + 2]  # +2 for z
                if self.this_op.vertices[offset + 1] < 0.0:
                    self.this_op.vertices[offset + 1] = 0.0
                self.this_op.vertices[offset + self.VELOCITY_I + 1] -= (
                    self.gravity / self.units_per_meter) / self.fps  # +1 for y
                self.this_op.vertices[
                    offset + self.ROTATION_I] += self.this_op.vertices[
                        offset + self.VELOCITY_I +
                        2] * 2  # +2 for z (spin according to speed and direction of z velocity)
            else:
                self.this_op.vertices[offset + self.VELOCITY_I] = 0.0
                self.this_op.vertices[offset + self.VELOCITY_I + 1] = 0.0
                self.this_op.vertices[offset + self.VELOCITY_I + 2] = 0.0
            offset += self.vertex_depth
        self.draw_mesh(None)

    def test_mesh_remove(self, dt):
        r = random()
        if r > .5:
            self.canvas.remove(self.mesh)
            self.mesh = None
        self.draw_mesh_points(60)

    def draw_mesh_points(self, number):
        self.star_list = []
        w, h = self.size
        sa = self.star_list.append
        for number in range(number):
            rand_x = random() * w
            rand_y = random() * h
            rand_z = random() * w
            rand_velocity = [
                random() * 10. - 5.,
                random() * 5. - 2.5,
                random() * 20. - 5.
            ]
            size = 29.0
            rotation = random() * 360.0
            this_v = (rand_x, rand_y, rand_z, size, rotation, rand_velocity[0],
                      rand_velocity[1], rand_velocity[2])
            if len(this_v) != self.vertex_depth:
                print(
                    "FATAL ERROR: tuple size does not match vertex depth (offset)"
                )
                exit(1)
            sa(this_v)
        self.draw_mesh(self.star_list)

    def draw_mesh(self, this_star_list):
        if self.this_op is None:
            self.this_op = PointRendererOp()
            star_tex = Image('star1.png').texture
            self.this_op.indices = []
            ia = self.this_op.indices.append
            for star_number in range(len(this_star_list)):
                ia(star_number)
            self.this_op.vertices = []
            e = self.this_op.vertices.extend
            for star in this_star_list:
                this_star = [ star[0], star[1], star[2], star[3], \
                              star[4], star[5], star[6], star[7] ]
                if len(this_star) != self.vertex_depth:
                    print("FATAL ERROR: array size does not match " + \
                          "vertex depth (offset)")
                    exit(1)
                e(this_star)
        if self.mesh == None:
            with self.canvas:
                PushMatrix()
                self.mesh = Mesh(indices=self.this_op.indices,
                                 vertices=self.this_op.vertices,
                                 fmt=self.vertex_format,
                                 mode='points',
                                 texture=star_tex)
                PopMatrix()
        else:
            # self.mesh.indices = self.this_op.indices
            self.mesh.vertices = self.this_op.vertices
            pass