Example #1
0
    def __init__(self, width, height):
        """:param width & height: size of the main window in pixels.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Polyhedra Mirrors",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self.shader = Shader([os.path.join(GLSL_DIR, "default.vert")], [
            os.path.join(GLSL_DIR, "common.frag"),
            os.path.join(GLSL_DIR, "data.frag"),
            os.path.join(GLSL_DIR, "main.frag")
        ])

        wood = create_image_texture(WOOD_IMAGE)
        cubemap = create_cubemap_texture(CUBEMAP_IMAGES)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_CUBE_MAP, cubemap)

        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, wood)

        with self.shader:
            self.shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shader.uniformf("iResolution", self.width, self.height, 0.0)
            self.shader.uniformf("iTime", 0.0)
            self.shader.uniformi("iChannel0", 0)
            self.shader.uniformi("iChannel1", 1)
Example #2
0
    def __init__(self, width, height, zoom):
        """
        :param width & height: size of the main window in pixels.
        :param zoom: zoom factor of the scene.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wang-Tile",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self.shader = Shader(["./glsl/default.vert"], ["./glsl/wang.frag"])

        cubemap = create_cubemap_texture(CUBEMAP_IMAGES)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_CUBE_MAP, cubemap)
        with self.shader:
            self.shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shader.uniformf("iResolution", self.width, self.height, 0.0)
            self.shader.uniformf("iTime", 0.0)
            self.shader.uniformf("zoom", zoom)
            self.shader.uniformi("iChannel0", 0)
Example #3
0
class WangTile(pyglet.window.Window):
    """
    Keyboard control:
        1. press Enter to save screenshots.
        2. press Esc to exit.
    """

    def __init__(self, width, height, zoom):
        """
        :param width & height: size of the main window in pixels.
        :param zoom: zoom factor of the scene.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wang-Tile",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self.shader = Shader(["./glsl/default.vert"], ["./glsl/wang.frag"])

        cubemap = create_cubemap_texture(CUBEMAP_IMAGES)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_CUBE_MAP, cubemap)
        with self.shader:
            self.shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shader.uniformf("iResolution", self.width, self.height, 0.0)
            self.shader.uniformf("iTime", 0.0)
            self.shader.uniformf("zoom", zoom)
            self.shader.uniformi("iChannel0", 0)

    def on_draw(self):
        gl.glClearColor(0, 0, 0, 0)
        self.clear()
        gl.glViewport(0, 0, self.width, self.height)
        with self.shader:
            self.shader.uniformf("iTime", time.perf_counter() - self._start_time)
            gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ENTER:
            self.save_screenshot()

        if symbol == key.ESCAPE:
            pyglet.app.exit()

    def save_screenshot(self):
        buff = pyglet.image.get_buffer_manager().get_color_buffer()
        buff.save("wangtile.png")

    def run(self, fps=None):
        self.set_visible(True)
        if fps is None:
            pyglet.clock.schedule(lambda dt: None)
        else:
            pyglet.clock.schedule_interval(lambda dt: None, 1.0 / fps)
        pyglet.app.run()
Example #4
0
class PolyhedraMirror(pyglet.window.Window):
    """
    Keyboard control:
        1. press Enter to save screenshots.
        2. press Esc to exit.
    """
    def __init__(self, width, height):
        """:param width & height: size of the main window in pixels.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Polyhedra Mirrors",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self.shader = Shader([os.path.join(GLSL_DIR, "default.vert")], [
            os.path.join(GLSL_DIR, "common.frag"),
            os.path.join(GLSL_DIR, "data.frag"),
            os.path.join(GLSL_DIR, "main.frag")
        ])

        wood = create_image_texture(WOOD_IMAGE)
        cubemap = create_cubemap_texture(CUBEMAP_IMAGES)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_CUBE_MAP, cubemap)

        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, wood)

        with self.shader:
            self.shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shader.uniformf("iResolution", self.width, self.height, 0.0)
            self.shader.uniformf("iTime", 0.0)
            self.shader.uniformi("iChannel0", 0)
            self.shader.uniformi("iChannel1", 1)

    def on_draw(self):
        gl.glClearColor(0, 0, 0, 0)
        self.clear()
        gl.glViewport(0, 0, self.width, self.height)
        with self.shader:
            self.shader.uniformf("iTime",
                                 time.perf_counter() - self._start_time)
            gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ENTER:
            self.save_screenshot()

        if symbol == key.ESCAPE:
            pyglet.app.exit()

    def on_mouse_press(self, x, y, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shader:
                self.shader.uniformf("iMouse", x, y, x, y)

    def on_mouse_release(self, x, y, button, modifiers):
        """Don't forget reset 'iMouse' when mouse is released.
        """
        with self.shader:
            self.shader.uniformf("iMouse", 0, 0, 0, 0)

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shader:
                x += dx
                y += dy
                x = max(min(x, self.width), 0)
                y = max(min(y, self.height), 0)
                self.shader.uniformf("iMouse", x, y, x, y)

    def save_screenshot(self):
        buff = pyglet.image.get_buffer_manager().get_color_buffer()
        buff.save("screenshot.png")

    def run(self, fps=None):
        self.set_visible(True)
        if fps is None:
            pyglet.clock.schedule(lambda dt: None)
        else:
            pyglet.clock.schedule_interval(lambda dt: None, 1.0 / fps)
        pyglet.app.run()
    def __init__(self, width, height):
        """
        :param width and height: size of the window in pixels.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wythoff Explorer",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self._last = self._now = self._start_time
        self._frame_count = 0  # count number of frames rendered so far
        self.shaderA = Shader(
            ["./glsl/default.vert"],
            [
                "./glsl/wythoff_hyperbolic/common.frag",
                "./glsl/wythoff_hyperbolic/BufferA.frag"
            ],
        )

        self.shaderB = Shader(
            ["./glsl/default.vert"],
            [
                "./glsl/wythoff_hyperbolic/common.frag",
                "./glsl/wythoff_hyperbolic/main.frag"
            ],
        )

        self.font_texture = create_image_texture(FONT_TEXTURE)
        self.noise_texture = create_image_texture(NOISE_TEXTURE)
        self.iChannel0 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB
        )
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.iChannel0.target, self.iChannel0.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.font_texture)
        gl.glActiveTexture(gl.GL_TEXTURE2)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.noise_texture)

        with FrameBuffer() as self.bufferA:
            self.bufferA.attach_texture(self.iChannel0)

        # initialize the shaders
        with self.shaderA:
            self.shaderA.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderA.uniformf("iResolution", width, height, 0.0)
            self.shaderA.uniformf("iTime", 0.0)
            self.shaderA.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderA.uniformi("iChannel0", 0)
            self.shaderA.uniformi("iChannel1", 1)
            self.shaderA.uniformi("iChannel2", 2)
            self.shaderA.uniformf("iDate", *get_idate())
            self.shaderA.uniformf("iTimeDelta", 0)

        with self.shaderB:
            self.shaderB.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderB.uniformf("iResolution", width, height, 0.0)
            self.shaderB.uniformf("iTime", 0.0)
            self.shaderB.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderB.uniformi("iChannel0", 0)
            self.shaderB.uniformi("iChannel1", 1)
            self.shaderB.uniformi("iChannel2", 2)
            self.shaderB.uniformf("iDate", *get_idate())
            self.shaderA.uniformf("iTimeDelta", 0)
class Wythoff(pyglet.window.Window):

    def __init__(self, width, height):
        """
        :param width and height: size of the window in pixels.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wythoff Explorer",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self._start_time = time.perf_counter()
        self._last = self._now = self._start_time
        self._frame_count = 0  # count number of frames rendered so far
        self.shaderA = Shader(
            ["./glsl/default.vert"],
            [
                "./glsl/wythoff_hyperbolic/common.frag",
                "./glsl/wythoff_hyperbolic/BufferA.frag"
            ],
        )

        self.shaderB = Shader(
            ["./glsl/default.vert"],
            [
                "./glsl/wythoff_hyperbolic/common.frag",
                "./glsl/wythoff_hyperbolic/main.frag"
            ],
        )

        self.font_texture = create_image_texture(FONT_TEXTURE)
        self.noise_texture = create_image_texture(NOISE_TEXTURE)
        self.iChannel0 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB
        )
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.iChannel0.target, self.iChannel0.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.font_texture)
        gl.glActiveTexture(gl.GL_TEXTURE2)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.noise_texture)

        with FrameBuffer() as self.bufferA:
            self.bufferA.attach_texture(self.iChannel0)

        # initialize the shaders
        with self.shaderA:
            self.shaderA.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderA.uniformf("iResolution", width, height, 0.0)
            self.shaderA.uniformf("iTime", 0.0)
            self.shaderA.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderA.uniformi("iChannel0", 0)
            self.shaderA.uniformi("iChannel1", 1)
            self.shaderA.uniformi("iChannel2", 2)
            self.shaderA.uniformf("iDate", *get_idate())
            self.shaderA.uniformf("iTimeDelta", 0)

        with self.shaderB:
            self.shaderB.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderB.uniformf("iResolution", width, height, 0.0)
            self.shaderB.uniformf("iTime", 0.0)
            self.shaderB.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderB.uniformi("iChannel0", 0)
            self.shaderB.uniformi("iChannel1", 1)
            self.shaderB.uniformi("iChannel2", 2)
            self.shaderB.uniformf("iDate", *get_idate())
            self.shaderA.uniformf("iTimeDelta", 0)

    def on_draw(self):
        gl.glClearColor(0, 0, 0, 0)
        self.clear()
        gl.glViewport(0, 0, self.width, self.height)
        self._last = self._now
        self._now = time.perf_counter()
        itime = self._now - self._start_time
        idate = get_idate()
        delta = self._now - self._last
        with self.bufferA:
            with self.shaderA:
                self.shaderA.uniformf("iTime", itime)
                self.shaderA.uniformf("iDate", *idate)
                self.shaderA.uniformf("iTimeDelta", delta)
                gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

        with self.shaderB:
            self.shaderB.uniformf("iTime", itime)
            self.shaderB.uniformf("iDate", *idate)
            self.shaderB.uniformf("iTimeDelta", delta)
            gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

        self._frame_count += 1

    def on_key_press(self, symbol, modifiers):
        """Keyboard interface.
        """
        if symbol == key.ENTER:
            self.save_screenshot()

        if symbol == key.ESCAPE:
            pyglet.app.exit()

    def on_mouse_press(self, x, y, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shaderA:
                self.shaderA.uniformf("iMouse", x, y, x, y)

    def on_mouse_release(self, x, y, button, modifiers):
        """Don't forget reset 'iMouse' when mouse is released.
        """
        with self.shaderA:
            self.shaderA.uniformf("iMouse", 0, 0, 0, 0)

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shaderA:
                x += dx
                y += dy
                x = max(min(x, self.width), 0)
                y = max(min(y, self.height), 0)
                self.shaderA.uniformf("iMouse", x, y, x, y)

    def save_screenshot(self):
        image_buffer = pyglet.image.get_buffer_manager().get_color_buffer()
        image_buffer.save("screenshoot.png")

    def run(self, fps=None):
        self.set_visible(True)
        if fps is None:
            pyglet.clock.schedule(lambda dt: None)
        else:
            pyglet.clock.schedule_interval(lambda dt: None, 1.0 / fps)
        pyglet.app.run()
Example #7
0
class GrayScott(pyglet.window.Window):
    """
    ----------------------------------------------------------
    | This simulation uses mouse and keyboard to control the |
    | patterns and colors. At any time you may click or drag |
    | your mouse to draw on the screen.                      |
    |                                                        |
    | Keyboard control:                                      |
    |   1. press "space" to clear the window to blank.       |
    |   2. press "p" to change to a random palette.          |
    |   3. press "s" to change to another species.           |
    |   4. press "Ctrl + s" to save current config.          |
    |   5. press "Ctrl + o" to load a config from the file.  |
    |   6. press "Enter" to take screenshots.                |
    |   7. press "Ctrl + v" to start saving the animation to |
    |      the video and press "Ctrl + v" again to stop.     |
    |   8. press "Esc" to exit.                              |
    ----------------------------------------------------------
    """
    def __init__(
        self,
        width,
        height,
        scale=1.5,
        conf=1,
        mask=None,
        flip=False,
        video=False,
        sample_rate=None,
        video_rate=None,
    ):
        """
        Parameters
        ----------
        :width & height: size of the window in pixels.
        :scale: scaling factor of the texture.
        :conf: line number of the config in the file (`config.txt`).
        :mask: a user-specified image that is used to control the growth of the pattern.
        :flip: flip the white/black pixels in the mask image, only meaningful if there is a mask image.
        :video: whether the video is turned on or off.
        :sample_rate: sample a frame from the animation every these frames.
        :video_rate: frames per second of the video.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="GrayScott Simulation",
            resizable=True,
            visible=False,
            vsync=False,
        )

        # use two shaders, one for doing the computations and one for rendering to the screen.
        self.reaction_shader = Shader(["./glsl/default.vert"],
                                      ["./glsl/grayscott/compute.frag"])
        self.render_shader = Shader(["./glsl/default.vert"],
                                    ["./glsl/grayscott/render.frag"])
        self.tex_width, self.tex_height = int(width / scale), int(height /
                                                                  scale)

        try:
            self.species, self.palette = self.load_config(conf)
            print("> Current species: " + self.species + "\n")
        except:
            conf = "unstable: #00000000 #00FF0033 #FFFF0035 #FF000066 #FFFFFF99"
            self.species, self.palette = parse(conf)
            print("> Failed to load the config, using the default one.\n")

        self.species_list = list(ALL_SPECIES.keys())

        # create the uv_texture
        uv_grid = np.zeros((self.tex_height, self.tex_width, 4),
                           dtype=np.float32)
        uv_grid[:, :, 0] = 1.0
        rand_rows = np.random.choice(range(self.tex_height), 5)
        rand_cols = np.random.choice(range(self.tex_width), 5)
        uv_grid[rand_rows, rand_cols, 1] = 1.0
        self.uv_texture = create_texture_from_ndarray(uv_grid)

        # create the mask_texture
        mask_grid = np.ones_like(uv_grid)
        if mask is not None:
            img = (Image.open(mask).convert("L").resize(
                (self.tex_width, self.tex_height)))
            img = (np.asarray(img) / 255.0).astype(np.float32)
            if flip:
                img = 1.0 - img
            mask_grid[:, :, 0] = img[::-1]
        self.mask_texture = create_texture_from_ndarray(mask_grid)

        # bind the two textures
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.uv_texture.target, self.uv_texture.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(self.mask_texture.target, self.mask_texture.id)

        # use an invisible buffer to do the computations.
        with FrameBuffer() as self.fbo:
            self.fbo.attach_texture(self.uv_texture)

        # we need this because the program samples the position of the mouse in discrete times.
        self.mouse_down = False

        # initialize the two shaders
        with self.reaction_shader:
            self.reaction_shader.vertex_attrib("position",
                                               [-1, -1, 1, -1, -1, 1, 1, 1])
            self.reaction_shader.vertex_attrib("texcoord",
                                               [0, 0, 1, 0, 0, 1, 1, 1])
            self.reaction_shader.uniformi("iChannel0", 0)
            self.reaction_shader.uniformi("mask_texture", 1)
            self.reaction_shader.uniformf("iResolution", self.tex_width,
                                          self.tex_height, 0)
            self.reaction_shader.uniformf("iMouse", -1, -1)
            self.reaction_shader.uniformf("params", *ALL_SPECIES[self.species])

        with self.render_shader:
            self.render_shader.vertex_attrib("position",
                                             [-1, -1, 1, -1, -1, 1, 1, 1])
            self.render_shader.vertex_attrib("texcoord",
                                             [0, 0, 1, 0, 0, 1, 1, 1])
            self.render_shader.uniformi("iChannel0", 0)
            self.render_shader.uniformfv("palette", 5, self.palette)

        self.video_on = video
        self.buffer = pyglet.image.get_buffer_manager().get_color_buffer()

        self.sample_rate = sample_rate
        self.video_rate = video_rate

        self.frame_count = 0

        if video:
            self.ffmpeg_pipe = self.create_new_pipe()

        self.start_time = time.perf_counter()

    def on_draw(self):
        gl.glClearColor(0.0, 0.0, 0.0, 0.0)
        self.clear()

        if time.perf_counter() - self.start_time > 0.1:
            gl.glViewport(0, 0, self.tex_width, self.tex_height)
            with self.fbo:
                with self.reaction_shader:
                    gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

            gl.glViewport(0, 0, self.width, self.height)
            with self.render_shader:
                gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
                self.frame_count += 1

        if self.video_on and (self.frame_count % self.sample_rate == 0):
            self.write_video_frame()

    def on_key_press(self, symbol, modifiers):
        """
        Keyboard interface.
        """
        if symbol == key.ENTER:
            self.save_screenshot()

        if symbol == key.ESCAPE:
            pyglet.app.exit()

        if symbol == key.SPACE:
            self.clear_blank_window()

        if symbol == key.P:
            self.use_random_palette()

        if symbol == key.S and not modifiers:
            self.use_next_species()

        if symbol == key.S and (modifiers & key.LCTRL):
            self.save_config()

        if symbol == key.O and (modifiers & key.LCTRL):
            self.require_config_input()

        if symbol == key.V and (modifiers & key.LCTRL):
            self.switch_video()

    def update_species(self, species):
        self.species = species
        with self.reaction_shader:
            self.reaction_shader.uniformf("params", *ALL_SPECIES[species])

    def update_palette(self, palette):
        self.palette = palette
        with self.render_shader:
            self.render_shader.uniformfv("palette", 5, palette)

    def update_mouse(self, x, y):
        with self.fbo:
            with self.reaction_shader:
                self.reaction_shader.uniformf("iMouse", x, y)

    def save_screenshot(self):
        self.buffer.save("screenshot-" + self.species + ".png")

    def save_config(self):
        with open("grayscott_config.txt", "a+") as f:
            f.write(self.species + ": " +
                    " ".join(rgba_to_htmlcolors(self.palette)) + "\n")
            print("> Config saved.\n")

    def load_config(self, k):
        with open("grayscott_config.txt", "r") as f:
            for i, line in enumerate(f.readlines()):
                if k == i:
                    return parse(line)
            print("> Config does not exist.\n")

    def require_config_input(self):
        try:
            k = int(
                input("> Enter the line number in the config file: ").strip())
        except ValueError:
            print("> Invalid input.\n")
            return

        try:
            species, palette = self.load_config(k)
            self.update_species(species)
            self.update_palette(palette)
            print("> Config loaded. Current species: " + self.species)
        except:
            return

    def write_video_frame(self):
        """
        Read frame data from buffer and write it to the video.
        """
        data = self.buffer.get_image_data().get_data("RGBA", -4 * self.width)
        self.ffmpeg_pipe.write(data)

    def on_mouse_press(self, x, y, button, modifiers):
        self.mouse_down = True
        self.update_mouse(x / self.width, y / self.height)

    def on_mouse_release(self, x, y, button, modifiers):
        self.mouse_down = False
        self.update_mouse(-1, -1)

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if self.mouse_down:
            self.update_mouse(x / self.width, y / self.height)

    def clear_blank_window(self):
        self.update_mouse(-10, -10)

    def use_random_palette(self):
        new_palette = np.random.random(20)
        new_palette[[3, 7, 11, 15, 19]] = sorted(np.random.random(5))
        new_palette[:3] = 0
        self.update_palette(new_palette)

    def use_next_species(self):
        index = self.species_list.index(self.species)
        new_species = self.species_list[(index + 1) % len(self.species_list)]
        self.update_species(new_species)
        print("> Current species: " + self.species + "\n")

    def switch_video(self):
        self.video_on = not self.video_on
        if self.video_on:
            self.ffmpeg_pipe = self.create_new_pipe()
            print("> Writing to video...\n")
        else:
            self.ffmpeg_pipe.close()
            print("> The video is closed.\n")

    def create_new_pipe(self):
        ffmpeg = subprocess.Popen(
            (
                FFMPEG_EXE,
                "-threads",
                "0",
                "-loglevel",
                "panic",
                "-r",
                "%d" % self.video_rate,
                "-f",
                "rawvideo",
                "-pix_fmt",
                "rgba",
                "-s",
                "%dx%d" % (self.width, self.height),
                "-i",
                "-",
                "-c:v",
                "libx264",
                "-crf",
                "20",
                "-y",
                self.species + ".mp4",
            ),
            stdin=subprocess.PIPE,
        )
        return ffmpeg.stdin

    def run(self, fps=None):
        self.set_visible(True)
        if fps is None:
            pyglet.clock.schedule(lambda dt: None)
        else:
            pyglet.clock.schedule_interval(lambda dt: None, 1.0 / fps)
        pyglet.app.run()
Example #8
0
    def __init__(
        self,
        width,
        height,
        scale=1.5,
        conf=1,
        mask=None,
        flip=False,
        video=False,
        sample_rate=None,
        video_rate=None,
    ):
        """
        Parameters
        ----------
        :width & height: size of the window in pixels.
        :scale: scaling factor of the texture.
        :conf: line number of the config in the file (`config.txt`).
        :mask: a user-specified image that is used to control the growth of the pattern.
        :flip: flip the white/black pixels in the mask image, only meaningful if there is a mask image.
        :video: whether the video is turned on or off.
        :sample_rate: sample a frame from the animation every these frames.
        :video_rate: frames per second of the video.
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="GrayScott Simulation",
            resizable=True,
            visible=False,
            vsync=False,
        )

        # use two shaders, one for doing the computations and one for rendering to the screen.
        self.reaction_shader = Shader(["./glsl/default.vert"],
                                      ["./glsl/grayscott/compute.frag"])
        self.render_shader = Shader(["./glsl/default.vert"],
                                    ["./glsl/grayscott/render.frag"])
        self.tex_width, self.tex_height = int(width / scale), int(height /
                                                                  scale)

        try:
            self.species, self.palette = self.load_config(conf)
            print("> Current species: " + self.species + "\n")
        except:
            conf = "unstable: #00000000 #00FF0033 #FFFF0035 #FF000066 #FFFFFF99"
            self.species, self.palette = parse(conf)
            print("> Failed to load the config, using the default one.\n")

        self.species_list = list(ALL_SPECIES.keys())

        # create the uv_texture
        uv_grid = np.zeros((self.tex_height, self.tex_width, 4),
                           dtype=np.float32)
        uv_grid[:, :, 0] = 1.0
        rand_rows = np.random.choice(range(self.tex_height), 5)
        rand_cols = np.random.choice(range(self.tex_width), 5)
        uv_grid[rand_rows, rand_cols, 1] = 1.0
        self.uv_texture = create_texture_from_ndarray(uv_grid)

        # create the mask_texture
        mask_grid = np.ones_like(uv_grid)
        if mask is not None:
            img = (Image.open(mask).convert("L").resize(
                (self.tex_width, self.tex_height)))
            img = (np.asarray(img) / 255.0).astype(np.float32)
            if flip:
                img = 1.0 - img
            mask_grid[:, :, 0] = img[::-1]
        self.mask_texture = create_texture_from_ndarray(mask_grid)

        # bind the two textures
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.uv_texture.target, self.uv_texture.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(self.mask_texture.target, self.mask_texture.id)

        # use an invisible buffer to do the computations.
        with FrameBuffer() as self.fbo:
            self.fbo.attach_texture(self.uv_texture)

        # we need this because the program samples the position of the mouse in discrete times.
        self.mouse_down = False

        # initialize the two shaders
        with self.reaction_shader:
            self.reaction_shader.vertex_attrib("position",
                                               [-1, -1, 1, -1, -1, 1, 1, 1])
            self.reaction_shader.vertex_attrib("texcoord",
                                               [0, 0, 1, 0, 0, 1, 1, 1])
            self.reaction_shader.uniformi("iChannel0", 0)
            self.reaction_shader.uniformi("mask_texture", 1)
            self.reaction_shader.uniformf("iResolution", self.tex_width,
                                          self.tex_height, 0)
            self.reaction_shader.uniformf("iMouse", -1, -1)
            self.reaction_shader.uniformf("params", *ALL_SPECIES[self.species])

        with self.render_shader:
            self.render_shader.vertex_attrib("position",
                                             [-1, -1, 1, -1, -1, 1, 1, 1])
            self.render_shader.vertex_attrib("texcoord",
                                             [0, 0, 1, 0, 0, 1, 1, 1])
            self.render_shader.uniformi("iChannel0", 0)
            self.render_shader.uniformfv("palette", 5, self.palette)

        self.video_on = video
        self.buffer = pyglet.image.get_buffer_manager().get_color_buffer()

        self.sample_rate = sample_rate
        self.video_rate = video_rate

        self.frame_count = 0

        if video:
            self.ffmpeg_pipe = self.create_new_pipe()

        self.start_time = time.perf_counter()
Example #9
0
    def __init__(self, width, height, aa=1, video_rate=16, sample_rate=4):
        """
        :param width and height: size of the window in pixels.

        :param aa: antialiasing level, a higher value will give better
            result but also slow down the animation. (aa=2 is recommended)
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wythoff Explorer",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self.video_rate = video_rate
        self.video_on = False
        self.sample_rate = sample_rate
        self._start_time = time.process_time()
        self._frame_count = 0  # count number of frames rendered so far
        self._speed = 4  # control speed of the animation
        self.aa = aa
        # shader A draws the UI
        self.shaderA = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/BufferA.frag"
        ])
        # shader B draws the polyhedra
        self.shaderB = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/BufferB.frag"
        ])
        # shader C puts them together
        self.shaderC = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/main.frag"
        ])
        self.font_texture = create_image_texture(FONT_TEXTURE)
        self.iChannel0 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB)
        self.iChannel1 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.iChannel0.target, self.iChannel0.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(self.iChannel1.target, self.iChannel1.id)
        gl.glActiveTexture(gl.GL_TEXTURE2)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.font_texture)

        # frame buffer A renders the UI to texture iChannel0
        with FrameBuffer() as self.bufferA:
            self.bufferA.attach_texture(self.iChannel0)
        # frame buffer B render the polyhedra to texture iChannel1
        with FrameBuffer() as self.bufferB:
            self.bufferB.attach_texture(self.iChannel1)

        # initialize the shaders

        with self.shaderA:
            self.shaderA.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderA.uniformf("iResolution", width, height, 0.0)
            self.shaderA.uniformf("iTime", 0.0)
            self.shaderA.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderA.uniformi("iChannel0", 0)
            self.shaderA.uniformi("iFrame", 0)

        with self.shaderB:
            self.shaderB.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderB.uniformf("iResolution", width, height, 0.0)
            self.shaderB.uniformf("iTime", 0.0)
            self.shaderB.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderB.uniformi("iChannel0", 0)
            self.shaderB.uniformi("AA", self.aa)

        with self.shaderC:
            self.shaderC.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderC.uniformf("iResolution", width, height, 0.0)
            self.shaderC.uniformf("iTime", 0.0)
            self.shaderC.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderC.uniformi("iChannel0", 0)
            self.shaderC.uniformi("iChannel1", 1)
            self.shaderC.uniformi("iChannel2", 2)
Example #10
0
class Wythoff(pyglet.window.Window):
    """
    User interface:
      1. use mouse click to play with the ui.
      2. press `Enter` to save screenshots.
      3. press `Ctrl+v` to start saving video and `Ctrl+v` again to stop.
      4. press `Esc` to exit.
    """
    def __init__(self, width, height, aa=1, video_rate=16, sample_rate=4):
        """
        :param width and height: size of the window in pixels.

        :param aa: antialiasing level, a higher value will give better
            result but also slow down the animation. (aa=2 is recommended)
        """
        pyglet.window.Window.__init__(
            self,
            width,
            height,
            caption="Wythoff Explorer",
            resizable=True,
            visible=False,
            vsync=False,
        )
        self.video_rate = video_rate
        self.video_on = False
        self.sample_rate = sample_rate
        self._start_time = time.process_time()
        self._frame_count = 0  # count number of frames rendered so far
        self._speed = 4  # control speed of the animation
        self.aa = aa
        # shader A draws the UI
        self.shaderA = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/BufferA.frag"
        ])
        # shader B draws the polyhedra
        self.shaderB = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/BufferB.frag"
        ])
        # shader C puts them together
        self.shaderC = Shader(["./glsl/default.vert"], [
            "./glsl/wythoff_polyhedra/common.frag",
            "./glsl/wythoff_polyhedra/main.frag"
        ])
        self.font_texture = create_image_texture(FONT_TEXTURE)
        self.iChannel0 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB)
        self.iChannel1 = pyglet.image.Texture.create_for_size(
            gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(self.iChannel0.target, self.iChannel0.id)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(self.iChannel1.target, self.iChannel1.id)
        gl.glActiveTexture(gl.GL_TEXTURE2)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.font_texture)

        # frame buffer A renders the UI to texture iChannel0
        with FrameBuffer() as self.bufferA:
            self.bufferA.attach_texture(self.iChannel0)
        # frame buffer B render the polyhedra to texture iChannel1
        with FrameBuffer() as self.bufferB:
            self.bufferB.attach_texture(self.iChannel1)

        # initialize the shaders

        with self.shaderA:
            self.shaderA.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderA.uniformf("iResolution", width, height, 0.0)
            self.shaderA.uniformf("iTime", 0.0)
            self.shaderA.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderA.uniformi("iChannel0", 0)
            self.shaderA.uniformi("iFrame", 0)

        with self.shaderB:
            self.shaderB.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderB.uniformf("iResolution", width, height, 0.0)
            self.shaderB.uniformf("iTime", 0.0)
            self.shaderB.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderB.uniformi("iChannel0", 0)
            self.shaderB.uniformi("AA", self.aa)

        with self.shaderC:
            self.shaderC.vertex_attrib("position",
                                       [-1, -1, 1, -1, -1, 1, 1, 1])
            self.shaderC.uniformf("iResolution", width, height, 0.0)
            self.shaderC.uniformf("iTime", 0.0)
            self.shaderC.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0)
            self.shaderC.uniformi("iChannel0", 0)
            self.shaderC.uniformi("iChannel1", 1)
            self.shaderC.uniformi("iChannel2", 2)

    def on_draw(self):
        gl.glClearColor(0, 0, 0, 0)
        self.clear()
        gl.glViewport(0, 0, self.width, self.height)
        now = time.process_time() - self._start_time
        now *= self._speed
        with self.bufferA:
            with self.shaderA:
                self.shaderA.uniformf("iTime", now)
                self.shaderA.uniformi("iFrame", self._frame_count)
                gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

        with self.bufferB:
            with self.shaderB:
                self.shaderB.uniformf("iTime", now)
                gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

        with self.shaderC:
            self.shaderC.uniformf("iTime", now)
            gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)

        if self.video_on and (self._frame_count % self.sample_rate == 0):
            self.write_video_frame()

        self._frame_count += 1

    def on_key_press(self, symbol, modifiers):
        """
        Keyboard interface.
        """
        if symbol == key.ENTER:
            self.save_screenshot()

        if symbol == key.ESCAPE:
            pyglet.app.exit()

        if symbol == key.V and (modifiers & key.LCTRL):
            self.switch_video()

    def on_mouse_press(self, x, y, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shaderA:
                self.shaderA.uniformf("iMouse", x, y, x, y)

    def on_mouse_release(self, x, y, button, modifiers):
        """
        Don't forget reset 'iMouse' when mouse is released.
        """
        with self.shaderA:
            self.shaderA.uniformf("iMouse", 0, 0, 0, 0)

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if button & pyglet.window.mouse.LEFT:
            with self.shaderA:
                x += dx
                y += dy
                x = max(min(x, self.width), 0)
                y = max(min(y, self.height), 0)
                self.shaderA.uniformf("iMouse", x, y, x, y)

    def save_screenshot(self):
        image_buffer = pyglet.image.get_buffer_manager().get_color_buffer()
        image_buffer.save("screenshot.png")

    def switch_video(self):
        self.video_on = not self.video_on
        if self.video_on:
            self.ffmpeg_pipe = self.create_new_pipe()
            print("> Writing to video...\n")
        else:
            self.ffmpeg_pipe.close()
            print("> The video is closed.\n")

    def write_video_frame(self):
        data = (pyglet.image.get_buffer_manager().get_color_buffer().
                get_image_data().get_data("RGBA", -4 * self.width))
        self.ffmpeg_pipe.write(data)

    def create_new_pipe(self):
        ffmpeg = subprocess.Popen(
            (
                FFMPEG_EXE,
                "-threads",
                "0",
                "-loglevel",
                "panic",
                "-r",
                "%d" % self.video_rate,
                "-f",
                "rawvideo",
                "-pix_fmt",
                "rgba",
                "-s",
                "%dx%d" % (self.width, self.height),
                "-i",
                "-",
                "-c:v",
                "libx264",
                "-crf",
                "20",
                "-y",
                "test.mp4",
            ),
            stdin=subprocess.PIPE,
        )
        return ffmpeg.stdin

    def run(self, fps=None):
        self.set_visible(True)
        if fps is None:
            pyglet.clock.schedule(lambda dt: None)
        else:
            pyglet.clock.schedule_interval(lambda dt: None, 1.0 / fps)
        pyglet.app.run()