Пример #1
0
    def run(cls):
        """Shortcut for running a ``WindowConfig``.

        This executes the following code::

            import moderngl_window
            moderngl_window.run_window_config(cls)
        """
        import moderngl_window
        moderngl_window.run_window_config(cls)
Пример #2
0
    def test_run_window_config(self):
        sys.argv = [
            'something',
            '-wnd',
            'headless',
            '--size_mult',
            '1.0',
            '--cursor',
            'False',
            '--size',
            '100x100',
        ]
        mglw.run_window_config(Config)

        self.assertIsInstance(mglw.window(), BaseWindow)
        self.assertIsInstance(mglw.ctx(), moderngl.Context)
Пример #3
0
        self.hmd.render(self.basic_lightHmd)
        self.hmd2.render(self.basic_lightHmd)

        self.basic_lightFloor['m_model'].write(Matrix44.from_translation((0, 0, 0), dtype='f4'))
        self.basic_lightFloor['m_proj'].write(self.camera.projection.matrix)
        self.basic_lightFloor['m_camera'].write(self.camera.matrix)
        self.basic_lightFloor['m_shadow_bias'].write(matrix44.multiply(depth_mvp, bias_matrix))
        self.basic_lightFloor['lightDir'].write(self.lightpos)

        self.floor.render(self.basic_lightFloor)

        # # Render the sun position
        # self.sun_prog['m_proj'].write(self.camera.projection.matrix)
        # self.sun_prog['m_camera'].write(self.camera.matrix)
        # self.sun_prog['m_model'].write(Matrix44.from_translation(self.lightpos + scene_pos, dtype='f4'))
        # self.sun.render(self.sun_prog)

        # --- PASS 3: Debug ---
        # self.ctx.enable_only(moderngl.NOTHING)
        self.offscreen_depth.use(location=0)
        self.offscreen_quad.render(self.raw_depth_prog)
        # self.offscreen_color.use(location=0)
        # self.offscreen_quad2.render(self.texture_prog)


if __name__ == '__main__':
    with myDriver:
        myDriver.send('hello')
        moderngl_window.run_window_config(ShadowMapping)
    print ('lol')
        # Generate per instance data represeting a grid of cubes
        N = 100
        self.instances = N * N

        def gen_data(x_res, z_res, spacing=2.5):
            """Generates a grid of N * N poistions and random colors on the xz plane"""
            for y in range(z_res):
                for x in range(x_res):
                    yield -N * spacing / 2 + spacing * x
                    yield 0
                    yield -N * spacing / 2 + spacing * y
                    yield numpy.random.uniform(0, 1)
                    yield numpy.random.uniform(0, 1)
                    yield numpy.random.uniform(0, 1)

        self.instance_data = self.ctx.buffer(numpy.fromiter(gen_data(N, N), 'f4', count=self.instances * 6))
        self.cube.buffer(self.instance_data, '3f 3f/i', ['in_offset', 'in_color'])

    def render(self, time: float, frametime: float):
        self.ctx.enable_only(moderngl.CULL_FACE | moderngl.DEPTH_TEST)

        self.prog['m_camera'].write(self.camera.matrix)
        self.prog['time'].value = time

        self.cube.render(self.prog, instances=self.instances)


if __name__ == '__main__':
    moderngl_window.run_window_config(CubeSimpleInstanced)
Пример #5
0
                                     aspect_ratio=self.wnd.aspect_ratio)
        self.camera_enabled = False
        self.render_program = self.load_program('my_shader.glsl')

        self.render_program['projection'].write(
            self.camera.projection.tobytes())
        self.render_program['m_camera'].write(
            self.camera.matrix.astype('f4').tobytes())
        self.cube = Cube(size=(.5, .5, .5))

    def render(self, time, frame_time):
        self.ctx.clear(51 / 255, 51 / 255, 51 / 255)
        self.ctx.enable_only(moderngl.DEPTH_TEST | moderngl.CULL_FACE)

        s = math.sin(time * 2) / 2 + 1.5

        self.cube.set_rotation(time, time / 2, time / 3)
        self.cube.set_translate(s * 4 - 6, 0, -3.0)

        self.render_program['model'].write(self.cube.matrix)
        self.render_program['m_camera'].write(self.camera.matrix.astype('f4'))
        self.cube.render(self.render_program)

    def resize(self, width: int, height: int):
        self.camera.projection.update(aspect_ratio=self.wnd.aspect_ratio)


if __name__ == '__main__':
    # noinspection PyTypeChecker
    mglw.run_window_config(CubeViz)
Пример #6
0
        self.zoom = 100
        self.n = 2**25
        self.program['n'].value = self.n
        primes = primesfrom2to(self.n)

        self.buffer = self.ctx.buffer(primes)
        self.vao1 = VAO(name='boids_1')
        self.vao1.buffer(self.buffer, '1i', ['in_prime'])

    def render(self, time, frame_time):
        r = g = b = 51 / 255
        self.ctx.clear(r, g, b)
        self.ctx.enable(moderngl.BLEND)
        self.ctx.blend_func = moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA

        self.program['n'].value = max((-f(time / 2**3) + 1) / 2 * self.n, 2000)

        self.vao1.render(self.program, mode=moderngl.POINTS)

    def key_event(self, key, action, modifiers):
        keys = self.wnd.keys

        if action == keys.ACTION_PRESS:
            if key == keys.SPACE:
                self.timer.toggle_pause()


if __name__ == '__main__':
    # noinspection PyTypeChecker
    mglw.run_window_config(PolarPrimes)
Пример #7
0
def main():
    mglw.run_window_config(Window)
Пример #8
0
                '2f 4f',
                'a_pos',
                'a_color',
            )],
        )

    def render(self, time, frametime):
        self.va.render(mode=mgl.LINES)

    def mouse_drag_event(self, x, y, dx, dy):
        self.u_pos.value = (
            self.u_pos.value[0] - dx / 640,
            self.u_pos.value[1] + dy / 480,
            self.u_pos.value[2],
        )

    def mouse_scroll_event(self, x_offset, y_offset):
        z = self.u_pos.value[2]
        if y_offset > 0:
            z /= 2
        else:
            z *= 2
        self.u_pos.value = (
            self.u_pos.value[0],
            self.u_pos.value[1],
            z,
        )


mglw.run_window_config(Config)
Пример #9
0
 def run(cls):
     mglw.run_window_config(cls)
Пример #10
0
import math
import moderngl_window


class BasicWindowConfig(moderngl_window.WindowConfig):
    """Minimal WindowConfig example"""
    gl_version = (3, 3)
    title = "Basic Window Config"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def render(self, time, frametime):
        self.ctx.clear(
            (math.sin(time) + 1.0) / 2,
            (math.sin(time + 2) + 1.0) / 2,
            (math.sin(time + 3) + 1.0) / 2,
        )


if __name__ == '__main__':
    moderngl_window.run_window_config(BasicWindowConfig)
Пример #11
0
        self.texture = self.ctx.texture(self.wnd.size, 3)
        self.fbo = self.ctx.simple_framebuffer(self.wnd.size)

        self.sample_i = 0
        self.sample_iu = self.path_prog['sample_i']
        self.aspect = self.path_prog['aspect']
        self.aspect.value = self.aspect_ratio
        self.scale = self.path_prog['scale']
        self.scale.value = np.tan(np.deg2rad(90) * 0.5)
        self.pixel_dim = self.path_prog['pixel_dim']
        self.pixel_dim.value = tuple(1 / np.array(self.wnd.size))

    def render(self, time, frame_time):
        self.fbo.clear(1, 1, 1)
        self.fbo.use()
        self.sample_iu.value = self.sample_i

        self.texture.use()
        self.path_vao.render()
        self.texture.write(self.fbo.read())

        self.ctx.clear(1.0, 1.0, 1.0)
        self.ctx.screen.use()
        self.texture.use()
        self.tex_vao.render()
        self.sample_i += 1


if __name__ == "__main__":
    mglw.run_window_config(PathTracer)
Пример #12
0
        self.n = 512

        self.voronoi_program = self.load_program('my_shader.glsl')
        self.voronoi_program['iResolution'].value = (self.wnd.buffer_size[0],
                                                     self.wnd.buffer_size[1])

        self.seeds = np.random.random_sample((self.n, 2))
        self.seeds_buffer = self.ctx.buffer(
            data=self.seeds.astype('f4').tobytes())

        colors = np.random.random_sample((self.n, 3))
        self.color_buffer = self.ctx.buffer(data=colors.astype('f4').tobytes())

        self.velocities = (np.random.random_sample((self.n, 2)) - .5) / 250

        self.voronoi_program['Seeds'].binding = 0
        self.voronoi_program['Colors'].binding = 1

    def render(self, time, frame_time):
        self.seeds_buffer.bind_to_uniform_block(0)
        self.color_buffer.bind_to_uniform_block(1)
        self.quad_fs.render(self.voronoi_program)
        self.seeds += self.velocities
        self.seeds = np.mod(self.seeds, 1)
        self.seeds_buffer.write(self.seeds.astype('f4').tobytes())


if __name__ == '__main__':
    # noinspection PyTypeChecker
    moderngl_window.run_window_config(Voronoi)
Пример #13
0
 def run(cls):
     mglw.run_window_config(cls)
     os._exit(1)  #Terminate python from thread
Пример #14
0
        self.scheduler = Scheduler(self.timer)

        # change the color every 1/2 seconds
        color_changing_event = self.scheduler.run_every(
            self.change_color, 1 / 2)
        # cancel the color changing event after 2 seconds using a priority of 2
        self.scheduler.cancel(color_changing_event, delay=2)
        # restart it after another 2 seconds (4 seconds total)
        color_changing_event = self.scheduler.run_every(self.change_color,
                                                        1 / 2,
                                                        initial_delay=4)

        # after 5 seconds change the window title
        self.scheduler.run_once(self.change_title,
                                5,
                                arguments=("Changed title", ))

    def change_title(self, new_title):
        self.wnd.title = new_title

    def change_color(self):
        self.clear_color = (random.random(), random.random(), random.random(),
                            0)

    def render(self, time: float, frametime: float):
        self.scheduler.execute()


if __name__ == "__main__":
    moderngl_window.run_window_config(CubeSimpleInstancedScheduler)
Пример #15
0
import math
import moderngl_window
from OpenGL import GL


class PyOpenGL(moderngl_window.WindowConfig):
    gl_version = (3, 3)
    title = "PyOpenGL"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def render(self, time, frametime):
        GL.glClearColor(
            (math.sin(time) + 1.0) / 2,
            (math.sin(time + 2) + 1.0) / 2,
            (math.sin(time + 3) + 1.0) / 2,
            1.0,
        )
        GL.glClear(GL.GL_COLOR_BUFFER_BIT)


if __name__ == '__main__':
    moderngl_window.run_window_config(PyOpenGL)
Пример #16
0
class TextureArrayExample(CameraWindow):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cube = geometry.cube(size=(2, 2, 2))
        self.texture = self.load_texture_array('textures/array.png',
                                               layers=10,
                                               mipmap=True,
                                               anisotrpy=8.0)
        self.prog = self.load_program('programs/cube_texture_array.glsl')

    def render(self, time: float, frametime: float):
        self.ctx.enable_only(moderngl.CULL_FACE | moderngl.DEPTH_TEST)

        m_rot = Matrix44.from_eulers(Vector3((time, time, time)))
        m_trans = matrix44.create_from_translation(Vector3((0.0, 0.0, -3.0)))
        m_mv = matrix44.multiply(m_rot, m_trans)

        self.prog['m_proj'].write(self.camera.projection.tobytes())
        self.prog['m_model'].write(m_mv.astype('f4').tobytes())
        self.prog['m_camera'].write(self.camera.matrix.astype('f4').tobytes())
        self.prog['layer'].value = math.fmod(time, 10)

        self.prog['texture0'].value = 0
        self.texture.use(location=0)
        self.cube.render(self.prog)


if __name__ == '__main__':
    mglw.run_window_config(TextureArrayExample)
Пример #17
0
        self.fractal_program['iter'].value = 1000
        self.fractal_program['R'].value = 2

        self.zoom = 1
        self.center = (0, 0)

    def render(self, time, frame_time):
        # self.fractal_program['time'].value = time

        # self.fractal_program['c'].value = (math.sin(time), math.cos(time))
        # self.zoom = ((math.sin(time / 2) + 1) / 2) * 1024 + 1
        self.fractal_program['center'].value = self.center
        self.fractal_program['zoom'].value = 1 / self.zoom
        self.quad_fs.render(self.fractal_program)

    def mouse_drag_event(self, x, y, dx, dy):
        self.center = ((self.center[0] - dx / self.zoom / self.window_size[0]),
                       (self.center[1] + dy / self.zoom / self.window_size[1]))

    def mouse_scroll_event(self, x_offset, y_offset):
        if y_offset > 0:
            self.zoom += self.zoom
        else:
            self.zoom -= math.log2(self.zoom)

        print(self.zoom)


if __name__ == '__main__':
    moderngl_window.run_window_config(Fractal)
Пример #18
0
                                               1000)
        lookat = Matrix44.look_at(
            (0, -1, 50),
            (0, 0, 0),
            (0, 0, 1),
        )
        self.projection.write((proj * lookat).astype('f4').tobytes())
        self.render_sprite(self.caveman_texture,
                           frame=int(time * 15) % self.caveman_texture.layers,
                           blend=True,
                           position=(0, 0))

    def render_sprite(self, texture, frame=0, blend=False, position=(0, 0)):
        if blend:
            self.ctx.enable(moderngl.BLEND)

        if self.wnd.frames < 10:
            print("self.wnd.frames: ", self.wnd.frames, "frame: ", frame)

        texture.use(location=0)
        self.sprite_program['layer_id'] = frame
        self.sprite_program['position'] = position
        self.sprite_geometry.render(self.sprite_program)

        if blend:
            self.ctx.disable(moderngl.BLEND)


if __name__ == '__main__':
    mglw.run_window_config(Test)
Пример #19
0
        lookat = Matrix44.look_at(
            tuple(camera_pos + self.origin),  # eye
            tuple(self.origin),  # target
            (0.0, 0.0, 1.0),  # up
        )

        self.mvp.write((proj * lookat).astype('f4'))
        self.ctx.point_size = 10
        self.vao.render(moderngl.POINTS)

    def mouse_drag_event(self, x, y, dx, dy):
        if self.mouse_button == 2:
            self.angleX += dx * -0.01
            self.angleY += dy * 0.01
            self.angleY = min(max(self.angleY, 0), (math.pi - 0.2) / 2)
        elif self.mouse_button == 1:
            self.origin += np.array([dy * -0.01, dx * -0.01, 0.0])

    def mouse_scroll_event(self, x_offset: float, y_offset: float):
        self.distance += y_offset * -0.1

    def mouse_press_event(self, x, y, button):
        self.mouse_button = button

    def mouse_release_event(self, x: int, y: int, button: int):
        self.mouse_button = 0


if __name__ == '__main__':
    mglw.run_window_config(MyExample)
Пример #20
0
This can be used to include reusable library functions.

We include a library doing different blend types
and render each quadrant of the screen with different blend types
"""
from pathlib import Path
import moderngl_window as mglw
from moderngl_window import geometry


class ShaderInclude(mglw.WindowConfig):
    title = "Shader Include"
    resource_dir = (Path(__file__) / '../../resources').resolve()
    aspect_ratio = 1

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.program = self.load_program('programs/blend_include.glsl')
        self.texture_0 = self.load_texture_2d('textures/cubemaps/yokohama/negx.jpg')
        self.texture_1 = self.load_texture_2d('textures/cubemaps/yokohama/negz.jpg')
        self.quad_fs = geometry.quad_fs()

    def render(self, time, frame_time):
        self.texture_0.use(location=0)
        self.texture_1.use(location=1)
        self.quad_fs.render(self.program)


if __name__ == '__main__':
    mglw.run_window_config(ShaderInclude)
Пример #21
0
        # Рисуем траектории тел.
        if not self.trail_render:  # Создаем рендер, если это не сделано.
            self.trail_render = TrailRender(ctx=self.ctx)

        self.trail_render.update(world=self.world)  # Запоминаем положения тел.
        self.trail_render.render(aspectratio=aspectratio,
                                 camera=self.camera)  # Рисуем все траектории.
        # ВНИМАНИЕ! Рисовать на каждом кадре всю траекторию целиком не оптимально.
        # Лучше рисовать траектории на отдельном framebuffer, который не будет очищаться на каждом кадре.
        # Тогда каждый раз будет достаточно рисовать только последний сегмент траектории, что значительно быстрее,
        # и позволит рисовать очень длинные траектории.
        # В этом примере мы не стали так делать, чтобы не вдаваться в детали работы OpenGL.

        # Теперь рисуем небесные тела.
        # Создаем рендер, если это еще не сделано.
        if not self.sprites_render:
            print(f"Resource directory: {self.resource_dir}")
            texture = self.load_texture_2d('symbols.jpg')
            self.sprites_render = SpriteRender(ctx=self.ctx, texture=texture)

        self.sprites_render.update(world=self.world)
        self.sprites_render.render(aspectratio=aspectratio, camera=self.camera)


#####################################################################################################################

if __name__ == '__main__':
    # Создаем окно приложения и запускаем симуляцию.
    mglw.run_window_config(Application)
Пример #22
0
        # self.camera.mouse_sensitivity = 0.3

        # Use this for gltf scenes for better camera controls
        if self.scene.diagonal_size > 0:
            self.camera.velocity = self.scene.diagonal_size / 5.0

    def render(self, time: float, frame_time: float):
        """Render the scene"""
        self.ctx.enable_only(moderngl.DEPTH_TEST | moderngl.CULL_FACE)

        # Move camera in on the z axis slightly by default
        translation = Matrix44.from_translation((0, 0, -1.5), dtype='f4')
        camera_matrix = self.camera.matrix * translation

        self.scene.draw(
            projection_matrix=self.camera.projection.matrix,
            camera_matrix=camera_matrix,
            time=time,
        )

        # Draw bounding boxes
        self.scene.draw_bbox(
            projection_matrix=self.camera.projection.matrix,
            camera_matrix=camera_matrix,
            children=True,
        )


if __name__ == '__main__':
    mglw.run_window_config(CubeModel)
Пример #23
0
            if key == keys.B:
                self.with_blending = not self.with_blending
                print("With blending:", self.with_blending)
                if self.with_blending:
                    self.mesh_color = 0.01, 0.01, 0.01
                    self.line_color = 0.01, 0.01, 0.01
                else:
                    self.mesh_color = 0.0, 0.8, 0.0
                    self.line_color = 0.0, 0.0, 0.0

    def mouse_scroll_event(self, x_offset, y_offset):
        if y_offset > 0:
            self.threshold += 0.01
        else:
            self.threshold -= 0.01

        self.threshold = max(min(self.threshold, 1.0), 0.0)

    def close(self):
        # 1 s = 1000000000 ns
        # 1 s = 1000000 μs
        avg = self.total_elapsed / self.wnd.frames
        print("Average rendering time per frame: {} ns | {} μs".format(
            round(avg, 4),  # ns
            round(avg / 1000, 4),  # μs
        ))


if __name__ == '__main__':
    moderngl_window.run_window_config(VolumetricTetrahedralMesh)
Пример #24
0
from moderngl_window import geometry

from base import CameraWindow


class GeometryBbox(CameraWindow):
    title = "BBox Geometry"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.wnd.mouse_exclusivity = True
        self.prog = self.load_program('scene_default/bbox.glsl')
        self.bbox = geometry.bbox()

        self.prog['color'].value = (1, 1, 1)
        self.prog['bb_min'].value = (-2, -2, -2)
        self.prog['bb_max'].value = (2, 2, 2)
        self.prog['m_model'].write(
            Matrix44.from_translation([0.0, 0.0, -8.0], dtype='f4'))

    def render(self, time: float, frame_time: float):
        self.ctx.clear()

        self.prog['m_proj'].write(self.camera.projection.matrix)
        self.prog['m_cam'].write(self.camera.matrix)
        self.bbox.render(self.prog)


if __name__ == '__main__':
    moderngl_window.run_window_config(GeometryBbox)
Пример #25
0
        self.cube = geometry.cube(size=(20, 20, 20))
        self.texture = self.load_texture_cube(
            neg_x='textures/cubemaps/yokohama/negx.jpg',
            neg_y='textures/cubemaps/yokohama/negy.jpg',
            neg_z='textures/cubemaps/yokohama/negz.jpg',
            pos_x='textures/cubemaps/yokohama/posx.jpg',
            pos_y='textures/cubemaps/yokohama/posy.jpg',
            pos_z='textures/cubemaps/yokohama/posz.jpg',
        )
        self.prog = self.load_program('programs/cubemap.glsl')

    def render(self, time, frame_time):
        self.ctx.enable_only(moderngl.CULL_FACE)
        self.ctx.front_face = 'cw'

        cam = self.camera.matrix
        # Purge camera translation
        cam[3][0] = 0
        cam[3][1] = 0
        cam[3][2] = 0

        self.texture.use(location=0)
        self.prog['m_proj'].write(self.camera.projection.matrix)
        self.prog['m_camera'].write(cam)

        self.cube.render(self.prog)


if __name__ == '__main__':
    moderngl_window.run_window_config(Cubemap)
Пример #26
0
            (math.sin(time + 3) + 1.0) / 2,
        )

        self.ctx.enable(moderngl.BLEND)
        self.pg_texture.use()
        self.quad_fs.render(self.texture_program)
        self.ctx.disable(moderngl.BLEND)

    def render_pygame(self, time):
        """Render to offscreen surface and copy result into moderngl texture"""
        self.pg_screen.fill((0, 0, 0, 0))  # Make sure we clear with alpha 0!
        N = 8
        for i in range(N):
            time_offset = 6.28 / N * i
            pygame.draw.circle(
                self.pg_screen,
                ((i * 50) % 255, (i * 100) % 255, (i * 20) % 255),
                (math.sin(time + time_offset) * 55 + self.pg_res[0] // 2,
                 math.cos(time + time_offset) * 55 + self.pg_res[1] // 2),
                math.sin(time) * 4 + 15,
            )

        # Get the buffer view of the Surface's pixels
        # and write this data into the texture
        texture_data = self.pg_screen.get_view('1')
        self.pg_texture.write(texture_data)


if __name__ == '__main__':
    moderngl_window.run_window_config(Pygame, args=('--window', 'pygame2'))
Пример #27
0
        # render the result to the screen
        self.ball.render(self.render_program, instances=self.N)

        # swap buffers
        self._toggle = not self._toggle
        self.buffer1.bind_to_storage_buffer(self._toggle)
        self.buffer2.bind_to_storage_buffer(not self._toggle)

    def load_compute(self, uri, consts):
        """ read compute shader code and set consts """
        with open(self.resource_dir / uri, 'r') as fp:
            content = fp.read()

        # feed constant values
        for key, value in consts.items():
            content = content.replace(f"0//%{key}%", str(value))

        return self.ctx.compute_shader(content)

    def generate_data(self):
        # balls start in the center of the box, add `*2` to the end for them to start everywhere
        positions = (np.random.random((self.N, 3)) - .5) * self.BOX_SIZE
        velocities = (np.random.random((self.N, 3)) - .5)
        velocities *= self.SPEED
        return np.column_stack((positions, velocities)).flatten().astype('f4')


if __name__ == '__main__':
    # noinspection PyTypeChecker
    mglw.run_window_config(ComputeShaderExample)
Пример #28
0
from pathlib import Path

import moderngl_window
from moderngl_window import geometry
from moderngl_window import resources

resources.register_dir((Path(__file__).parent / 'resources').resolve())


class QuadFullscreen(moderngl_window.WindowConfig):
    window_size = 1980, 1024
    aspect_ratio = 1980 / 1024

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.quad = geometry.quad_fs()
        self.texture = self.load_texture_2d('textures/python-bg.png')
        self.prog = self.load_program('programs/texture.glsl')

    def render(self, time: float, frame_time: float):
        self.ctx.clear()

        self.texture.use(location=0)
        self.prog['texture0'].value = 0
        self.quad.render(self.prog)


if __name__ == '__main__':
    moderngl_window.run_window_config(QuadFullscreen)
Пример #29
0
 def run(cls):
     moderngl_window.run_window_config(cls)
Пример #30
0
from moderngl_window import geometry


class Gradient(moderngl_window.WindowConfig):
    title = "Gradient"
    resource_dir = (Path(__file__) / '../resources').absolute()
    aspect_ratio = None
    window_size = 720, 720
    resizable = False
    samples = 16

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.quad_fs = geometry.quad_fs()

        self.gradient_program = self.load_program('my_shader.glsl')
        self.gradient_program['wnd_size'].value = self.wnd.buffer_size

        # change this if you want it to go faster/slower
        self.gradient_program['speed'].value = 7.5

    def render(self, time, frame_time):
        self.gradient_program['time'].value = time
        self.quad_fs.render(self.gradient_program)


if __name__ == '__main__':
    # noinspection PyTypeChecker
    moderngl_window.run_window_config(Gradient)