Example #1
0
class MandelbrotRenderer(object):
    transition_time = 0.3  # seconds
    update_step = 10  # milliseconds

    def __init__(self):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.window.mouse_callback = self.mouse
        self.shader = ShaderProgram(vertex=vertex_shader,
                                    fragment=fragment_shader)
        self.shader.colormap = Texture1D(cm.spectral(linspace(0, 1, 256)),
                                         wrap_s="MIRRORED_REPEAT")
        self.shader.minval = (-2.5, -1.75)
        self.shader.maxval = (1.0, 1.75)
        self.vao = get_fullscreen_quad()
        self.history = []

    def display(self):
        self.window.clear()
        self.vao.draw()
        self.window.swap_buffers()

    def timer(self):
        t = min(1.0, (get_elapsed_time() - self.transition_start) /
                self.transition_time)
        x = 0.5 - 0.5 * cos(pi * t)
        self.shader.minval = self.minstart * (1 - x) + self.minend * x
        self.shader.maxval = self.maxstart * (1 - x) + self.maxend * x
        if t < 1:
            self.window.add_timer(self.update_step, self.timer)
        self.window.post_redisplay()

    def start_transition(self, minval, maxval):
        self.minstart, self.maxstart = self.shader.minval, self.shader.maxval
        self.minend, self.maxend = minval, maxval
        self.transition_start = get_elapsed_time()
        self.timer()

    def mouse(self, button, state, x, y):
        if button == glut.GLUT_LEFT_BUTTON:
            pos = array(
                (x, self.window.shape[0] - y)) / array(self.window.shape[::-1],
                                                       dtype=float)
            pos = pos * (self.shader.maxval -
                         self.shader.minval) + self.shader.minval
            if state == glut.GLUT_DOWN:
                self.last_pos = pos
            elif state == glut.GLUT_UP and all(pos != self.last_pos):
                self.history.append((self.shader.minval, self.shader.maxval))
                self.start_transition(minimum(pos, self.last_pos),
                                      maximum(pos, self.last_pos))
        elif state == glut.GLUT_DOWN and button == glut.GLUT_RIGHT_BUTTON:
            if self.history:
                self.start_transition(*self.history.pop())

    def run(self):
        with self.shader:
            main_loop()
Example #2
0
class MandelbrotRenderer(object):
    transition_time = 0.3 # seconds
    update_step = 10 # milliseconds

    def __init__(self):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.window.mouse_callback = self.mouse
        self.shader = ShaderProgram(vertex=vertex_shader, fragment=fragment_shader)
        self.shader.colormap = Texture1D(cm.spectral(linspace(0, 1, 256)), wrap_s="MIRRORED_REPEAT")
        self.shader.minval = (-2.5, -1.75)
        self.shader.maxval = (1.0, 1.75)
        self.vao = get_fullscreen_quad()
        self.history = []

    def display(self):
        self.window.clear()
        self.vao.draw()
        self.window.swap_buffers()

    def timer(self):
        t = min(1.0, (get_elapsed_time() - self.transition_start) / self.transition_time)
        x = 0.5 - 0.5 * cos(pi * t)
        self.shader.minval = self.minstart * (1 - x) + self.minend * x
        self.shader.maxval = self.maxstart * (1 - x) + self.maxend * x
        if t < 1:
            self.window.add_timer(self.update_step, self.timer)
        self.window.post_redisplay()

    def start_transition(self, minval, maxval):
        self.minstart, self.maxstart = self.shader.minval, self.shader.maxval
        self.minend, self.maxend = minval, maxval
        self.transition_start = get_elapsed_time()
        self.timer()

    def mouse(self, button, state, x, y):
        if button == glut.GLUT_LEFT_BUTTON:
            pos = array((x, self.window.shape[0] - y)) / array(self.window.shape[::-1], dtype=float)
            pos = pos * (self.shader.maxval - self.shader.minval) + self.shader.minval
            if state == glut.GLUT_DOWN:
                self.last_pos = pos
            elif state == glut.GLUT_UP and all(pos != self.last_pos):
                self.history.append((self.shader.minval, self.shader.maxval))
                self.start_transition(minimum(pos, self.last_pos), maximum(pos, self.last_pos))
        elif state == glut.GLUT_DOWN and button == glut.GLUT_RIGHT_BUTTON:
            if self.history:
                self.start_transition(*self.history.pop())

    def run(self):
        with self.shader:
            main_loop()
Example #3
0
class DepthViewer(object):
    def __init__(self, filename):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.shader = get_default_program()
        self.fbo = Framebuffer(
            depth=Texture2D(shape=self.window.shape + (1, ), depth=True))
        self.copy_pipeline = get_copy_pipeline_2d(image=self.fbo.depth,
                                                  use_framebuffer=False)
        with h5py.File(filename, "r") as f:
            vertices = f["vertices"]
            colors = f.get("colors", None)
            elements = f.get("indices", None)
            if colors is None:
                colors = random(
                    (len(vertices), 3))[:, None, :][:,
                                                    [0] * vertices.shape[1], :]
            self.vao = VertexArray(vertices, colors, elements=elements)

    def display(self):
        try:
            with self.fbo:
                self.fbo.clear()
                self.vao.draw()
            self.window.clear()
            self.copy_pipeline.draw()
            self.window.swap_buffers()
        except Exception as e:
            import traceback
            traceback.print_exc()
            raise SystemExit(e)

    def timer(self):
        phi = 2 * pi * get_elapsed_time() / 20.0
        self.shader.modelview_matrix = ((cos(phi), 0, sin(phi), 0),
                                        (0, 1, 0, 0), (-sin(phi), 0, cos(phi),
                                                       0), (0, 0, 0, 1))
        self.window.add_timer(10, self.timer)
        self.window.post_redisplay()

    def run(self):
        self.timer()
        with self.shader:
            with State(depth_test=True):
                main_loop()
Example #4
0
class DepthViewer(object):
    def __init__(self, filename):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.shader = get_default_program()
        self.fbo = Framebuffer(depth=Texture2D(shape=self.window.shape + (1,), depth=True))
        self.copy_pipeline = get_copy_pipeline_2d(image=self.fbo.depth, use_framebuffer=False)
        with h5py.File(filename, "r") as f:
            vertices = f["vertices"]
            colors = f.get("colors", None)
            elements = f.get("indices", None)
            if colors is None:
                colors = random((len(vertices), 3))[:, None, :][:, [0] * vertices.shape[1], :]
            self.vao = VertexArray(vertices, colors, elements=elements)

    def display(self):
        try:
            with self.fbo:
                self.fbo.clear()
                self.vao.draw()
            self.window.clear()
            self.copy_pipeline.draw()
            self.window.swap_buffers()
        except Exception as e:
            import traceback
            traceback.print_exc()
            raise SystemExit(e)

    def timer(self):
        phi = 2 * pi * get_elapsed_time() / 20.0
        self.shader.modelview_matrix = ((cos(phi), 0, sin(phi), 0), (0, 1, 0, 0), (-sin(phi), 0, cos(phi), 0), (0, 0, 0, 1))
        self.window.add_timer(10, self.timer)
        self.window.post_redisplay()
    
    def run(self):
        self.timer()
        with self.shader:
            with State(depth_test=True):
                main_loop()
Example #5
0
class IntroductionExample(object):
    fps_scale = 1.1

    def __init__(self, images):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard
        self.window.special_callback = self.special
        self.images = images
        self.window.shape = self.images[0].shape[:2]
        self.render_pipeline = get_copy_pipeline_2d(
            context=self.window,
            sampler_type="isampler2D",
            maxval=255,
            yscale=-1,
            use_framebuffer=False,
            image=Texture2D(self._prepare_image(0)))
        self.current_index = 0
        self.fps = 25
        self.playing = False

    def _prepare_image(self, idx):
        img = self.images[idx]
        while img.ndim < 3:
            img = img[..., None]
        return img

    def display(self):
        self.window.clear()
        self.render_pipeline.image.data = self._prepare_image(
            self.current_index)
        self.window.window_title = self.images.filenames[
            self.current_index].filename
        self.render_pipeline.draw()
        self.window.swap_buffers()

    def keyboard(self, key, x, y):
        key = chr(key)
        if key == "+":
            self.fps *= self.fps_scale
        elif key == "-":
            self.fps /= self.fps_scale
        elif key == " ":
            if self.playing:
                self.playing = False
            else:
                self.playing = True
                self.timer()
        elif key == chr(27):
            raise SystemExit

    def special(self, key, x, y):
        if key == _gl.GLUT_KEY_LEFT:
            self.current_index = (self.current_index - 1) % len(self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_RIGHT:
            self.current_index = (self.current_index + 1) % len(self.images)
            self.window.post_redisplay()
        if key == _gl.GLUT_KEY_PAGE_UP:
            self.current_index = (self.current_index - self.fps) % len(
                self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_PAGE_DOWN:
            self.current_index = (self.current_index + self.fps) % len(
                self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_HOME:
            self.current_index = 0
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_END:
            self.current_index = len(self.images) - 1
            self.window.post_redisplay()

    def timer(self):
        if self.playing:
            self.current_index = (self.current_index + 1) % len(self.images)
            self.window.add_timer(int(round(1000.0 / self.fps)), self.timer)
            self.window.post_redisplay()

    def run(self):
        self.timer()
        main_loop()
Example #6
0
class IntroductionExample(object):
    # <h3>Initialization</h3>

    # When an <code>IntroductionExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display and keyboard callback functions which
        # will be defined later.
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard

        # A shader program is built from the previously defined vertex and
        # fragment codes:
        self.shader = ShaderProgram(vertex=vertex_shader, fragment=fragment_shader)

        # This shader program is then used to build a pipeline. A pipeline is a
        # convenience object that encapsulates a vertex array for input, a
        # shader program for processing, and a framebuffer for output. The
        # framebuffer is optional (we could render directly to the screen if we
        # wanted), but we will render into a texture and copy the texture to
        # the screen for instructional purposes. The <code>Pipeline</code>
        # constructor automatically creates an empty vertex array and a
        # framebuffer with no attachments. Named constructor arguments are
        # interpreted as attributes of the vertex array and the framebuffer or
        # as named inputs and outputs of the shader. This means we can directly
        # pass in arrays of vertices and colors that will be bound to
        # <code>in_position</code> and <code>in_color</code>, respectivey, as
        # well as the array of element indices to draw and an empty texture to
        # bind to the framebuffer:
        self.render_pipeline = Pipeline(self.shader, in_position=vertices, in_color=colors,
                elements=indices, out_color=RectangleTexture(shape=(300, 300, 3)))

        # Shader uniform variables like textures can also be set directly on
        # the pipeline. Here we initialize two textures with random data:
        self.render_pipeline.texture_0 = Texture2D(random((30, 30, 4)))
        self.render_pipeline.texture_1 = RectangleTexture(random((30, 30, 4)))

        # Many properties, such as the filtering mode for textures, can
        # directly be set as attributes on the corresponding objects:
        self.render_pipeline.texture_0.min_filter = Texture2D.min_filters.NEAREST
        self.render_pipeline.texture_0.mag_filter = Texture2D.mag_filters.NEAREST

        # For copying the texture to the screen, we create another shader
        # program.
        self.copy_shader = ShaderProgram(vertex=copy_vertex_shader, fragment=copy_fragment_shader)

        # The input texture of this shader program is the output texture of the
        # previous pipeline. Since all textures and framebuffers are
        # automatically bound and unbound, we do not need to worry about
        # whether the framebuffer is still writing to the texture.
        self.copy_shader.image = self.render_pipeline.out_color

        # Instead of using a pipeline with named vertex shader inputs, we can
        # also create a vertex array object directly with a list of vertex
        # shader inputs to use. Here we use only a single vertex shader input:
        # the coordinates of a fullscreen quad. The <code>elements</code>
        # parameter defines two triangles that make up the quad.
        self.vao = VertexArray(((-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0), (1.0, -1.0)), elements=((0, 1, 2), (0, 2, 3)))

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever
    # the screen has to be redrawn.
    def display(self):
        # We can simply clear the pipeline and render the vertices into the
        # framebuffer using the shader with the following two lines:
        self.render_pipeline.clear()
        self.render_pipeline.draw()

        # For output on the screen, we have created a GLUT window. It can be
        # cleared in very much the same way:
        self.window.clear()

        # To copy the results of the pipeline to the screen, we use the shader
        # that simply displays a texture. The shader can be bound by using a
        # <code>with</code> statement:
        with self.copy_shader:
            # All textures used by the shader are then bound automatically, and
            # everything is reset to its previous state when we leave the
            # <code>with</code> block.

            # With the shader bound, we simply draw a fullscreen quad that is
            # stored in a vertex array we will create in the initialization
            # section:
            self.vao.draw()

        # After all rendering commands have been issued, we swap the back
        # buffer to the front, making the rendered image visible all at once:
        self.window.swap_buffers()

        # Finally, we disable logging so that we only see the OpenGL calls of
        # the first run of the display function:
        add_logger(None)

    # <h4>Keyboard function</h4>

    # To further illustrate the concept of GLUT callbacks, here's a keyboard
    # handler that will simply make the program exit when any key is pressed:
    def keyboard(self, key, x, y):
        raise SystemExit

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes
    # the modelview matrix, schedules the next timer event, and causes a screen
    # redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using
        # <code>get_elapsed_time()</code>:
        t = get_elapsed_time()
        phi = 2 * pi * t / 4.0

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), sin(phi), 0, 0), (-sin(phi), cos(phi), 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))

        # The following line schedules the next timer event to execute after
        # ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>
    
    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # Now that all the initialization is done, we add the default logger to
        # all OpenGL commands so that we can see what OpenGL the display
        # function issues, and in which order.
        add_logger()

        # Finally, to start rendering, we enter the GLUT main loop.
        main_loop()
Example #7
0
class SimpleExample(object):
    # <h3>Initialization</h3>

    # When a <code>SimpleExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display callback function which will be defined
        # later.
        self.window.display_callback = self.display

        # We also set mouse callbacks that will display the pixel color in the
        # title bar.
        self.window.mouse_callback = self.mouse
        self.window.motion_callback = self.motion

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # Here, we create a vertex array that contains buffers for two vertex array
        # input variables as well as an index array:
        self.vao = VertexArray(vertices, colors, elements=indices)

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()

        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Mouse functions</h4>

    # The motion callback is called when the mouse is moved while a button is
    # pressed. It reads the current color of the pixel under the cursor from
    # the front buffer and displays it in the window title.
    def motion(self, x, y):
        self.window.window_title = "%.2f, %.2f, %.2f, %.2f" % tuple(
            self.window.front_pixels[self.window.shape[0] - y, x])

    # The mouse callback is called whenever a mouse button is pressed. It
    # redirects to the functionality of the motion callback.
    def mouse(self, button, state, x, y):
        self.motion(x, y)

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes the
    # modelview matrix, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using <code>get_elapsed_time()</code>:
        phi = get_elapsed_time()

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), sin(phi), 0,
                                         0), (-sin(phi), cos(phi), 0, 0),
                                        (0, 0, 1, 0), (0, 0, 0, 2))

        # The following line schedules the next timer event to execute after ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>

    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement:
        with self.shader:
            # With the shader bound, we enter the GLUT main loop.
            main_loop()
Example #8
0
class MeshViewer(object):
    # <h3>Initialization</h3>

    # When a <code>MeshViewer</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self, filename):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display callback function which will be defined later.
        self.window.display_callback = self.display

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # We open the HDF5 file specified on the command line for reading:
        if filename.endswith(".dat"):
            data = loadtxt(filename)
            assert data.ndim == 2 and data.shape[1] in (3, 6)

            vertices = data[:, :3]
            vertices -= vertices.min()
            vertices /= vertices.max()
            vertices -= 0.5
            
            colors = data[:, 3:] if data.shape[1] == 6 else None
            colors -= colors.min()
            colors /= colors.max()
            
            elements = None
        else:
            with h5py.File(filename, "r") as f:
                # The vertices, colors and indices of the mesh are read from the
                # corresponding datasets in the HDF5 file. Note that the names of the
                # datasets are mere convention. Colors and indices are allowed to be
                # undefined.
                vertices = f["vertices"]
                colors = f.get("colors", None)
                elements = f.get("indices", None)
                if vertices is not None:
                    vertices = vertices.value
                if colors is not None:
                    colors = colors.value
                if elements is not None:
                    elements = elements.value

        # If no colors were specified, we generate random ones so we can
        # distinguish the triangles without fancy shading.
        if colors is None:
            colors = random((len(vertices), 3))[:, None, :][:, [0] * vertices.shape[1], :]

        # Here, we create a vertex array that contains buffers for two vertex array
        # input variables as well as an index array. If <code>elements</code>
        # is <code>None</code>, the vertex array class will draw all vertices
        # in order.
        self.vao = VertexArray(vertices, colors, elements=elements)

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()

        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes the
    # modelview matrix, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using <code>get_elapsed_time()</code>:
        phi = 2 * pi * get_elapsed_time() / 20.0

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader simply by setting an attribute:
        self.shader.modelview_matrix = ((cos(phi), 0, sin(phi), 0), (0, 1, 0, 0), (-sin(phi), 0, cos(phi), 0), (0, 0, 0, 1))

        # The following line schedules the next timer event to execute after ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>
    
    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The shader program is bound by using a <code>with</code> statement:
        with self.shader:
            # The <code>State</code> class encapsulates state changes in the
            # context. For example, to enable depth testing for the duration of the
            # following function call, we would write:
            with State(depth_test=True):
                # With the shader bound and depth testing enabled, we enter the
                # GLUT main loop.
                main_loop()
Example #9
0
class IntroductionExample(object):
    # <h3>Initialization</h3>

    # When an <code>IntroductionExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display and keyboard callback functions which
        # will be defined later.
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard

        # A shader program is built from the previously defined vertex and
        # fragment codes:
        self.shader = ShaderProgram(vertex=vertex_shader,
                                    fragment=fragment_shader)

        # This shader program is then used to build a pipeline. A pipeline is a
        # convenience object that encapsulates a vertex array for input, a
        # shader program for processing, and a framebuffer for output. The
        # framebuffer is optional (we could render directly to the screen if we
        # wanted), but we will render into a texture and copy the texture to
        # the screen for instructional purposes. The <code>Pipeline</code>
        # constructor automatically creates an empty vertex array and a
        # framebuffer with no attachments. Named constructor arguments are
        # interpreted as attributes of the vertex array and the framebuffer or
        # as named inputs and outputs of the shader. This means we can directly
        # pass in arrays of vertices and colors that will be bound to
        # <code>in_position</code> and <code>in_color</code>, respectivey, as
        # well as the array of element indices to draw and an empty texture to
        # bind to the framebuffer:
        self.render_pipeline = Pipeline(self.shader,
                                        in_position=vertices,
                                        in_color=colors,
                                        elements=indices,
                                        out_color=RectangleTexture(shape=(300,
                                                                          300,
                                                                          3)))

        # Shader uniform variables like textures can also be set directly on
        # the pipeline. Here we initialize two textures with random data:
        self.render_pipeline.texture_0 = Texture2D(random((30, 30, 4)))
        self.render_pipeline.texture_1 = RectangleTexture(random((30, 30, 4)))

        # Many properties, such as the filtering mode for textures, can
        # directly be set as attributes on the corresponding objects:
        self.render_pipeline.texture_0.min_filter = Texture2D.min_filters.NEAREST
        self.render_pipeline.texture_0.mag_filter = Texture2D.mag_filters.NEAREST

        # For copying the texture to the screen, we create another shader
        # program.
        self.copy_shader = ShaderProgram(vertex=copy_vertex_shader,
                                         fragment=copy_fragment_shader)

        # The input texture of this shader program is the output texture of the
        # previous pipeline. Since all textures and framebuffers are
        # automatically bound and unbound, we do not need to worry about
        # whether the framebuffer is still writing to the texture.
        self.copy_shader.image = self.render_pipeline.out_color

        # Instead of using a pipeline with named vertex shader inputs, we can
        # also create a vertex array object directly with a list of vertex
        # shader inputs to use. Here we use only a single vertex shader input:
        # the coordinates of a fullscreen quad. The <code>elements</code>
        # parameter defines two triangles that make up the quad.
        self.vao = VertexArray(
            ((-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0), (1.0, -1.0)),
            elements=((0, 1, 2), (0, 2, 3)))

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever
    # the screen has to be redrawn.
    def display(self):
        # We can simply clear the pipeline and render the vertices into the
        # framebuffer using the shader with the following two lines:
        self.render_pipeline.clear()
        self.render_pipeline.draw()

        # For output on the screen, we have created a GLUT window. It can be
        # cleared in very much the same way:
        self.window.clear()

        # To copy the results of the pipeline to the screen, we use the shader
        # that simply displays a texture. The shader can be bound by using a
        # <code>with</code> statement:
        with self.copy_shader:
            # All textures used by the shader are then bound automatically, and
            # everything is reset to its previous state when we leave the
            # <code>with</code> block.

            # With the shader bound, we simply draw a fullscreen quad that is
            # stored in a vertex array we will create in the initialization
            # section:
            self.vao.draw()

        # After all rendering commands have been issued, we swap the back
        # buffer to the front, making the rendered image visible all at once:
        self.window.swap_buffers()

        # Finally, we disable logging so that we only see the OpenGL calls of
        # the first run of the display function:
        add_logger(None)

    # <h4>Keyboard function</h4>

    # To further illustrate the concept of GLUT callbacks, here's a keyboard
    # handler that will simply make the program exit when any key is pressed:
    def keyboard(self, key, x, y):
        raise SystemExit

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes
    # the modelview matrix, schedules the next timer event, and causes a screen
    # redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using
        # <code>get_elapsed_time()</code>:
        t = get_elapsed_time()
        phi = 2 * pi * t / 4.0

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), sin(phi), 0,
                                         0), (-sin(phi), cos(phi), 0, 0),
                                        (0, 0, 1, 0), (0, 0, 0, 1))

        # The following line schedules the next timer event to execute after
        # ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>

    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # Now that all the initialization is done, we add the default logger to
        # all OpenGL commands so that we can see what OpenGL the display
        # function issues, and in which order.
        add_logger()

        # Finally, to start rendering, we enter the GLUT main loop.
        main_loop()
Example #10
0
class PointcloudRenderer(object):
    # <h3>Initialization</h3>

    # When a <code>PointcloudRenderer</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display callback function which will be defined later.
        self.window.display_callback = self.display

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # Here, we create a vertex array that contains buffers for two vertex array
        # input variables as well as an index array:
        n_points = 100000
        self.vao = VertexArray(randn(n_points, 3), randn(n_points, 3))

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()

        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes the
    # modelview matrix, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using <code>get_elapsed_time()</code>:
        phi = 2 * pi * get_elapsed_time() / 20.0

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), 0, sin(phi), 0),
                                        (0, 1, 0, 0), (-sin(phi), 0, cos(phi),
                                                       0), (0, 0, 0, 5))

        # The following line schedules the next timer event to execute after ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>

    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement:
        with self.shader:
            # The <code>State</code> class encapsulates state changes in the
            # context. For example, to enable depth testing and set the point size
            # to three for the duration of the following function call, we would
            # write:
            with State(depth_test=True, point_size=3):
                # With the shader bound, depth testing enabled, and the point size
                # set, we enter the GLUT main loop.
                main_loop()
Example #11
0
class IntroductionExample(object):
    fps_scale = 1.1

    def __init__(self, images):
        self.window = GlutWindow(double=True, multisample=True)
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard
        self.window.special_callback = self.special
        self.images = images
        self.window.shape = self.images[0].shape[:2]
        self.render_pipeline = get_copy_pipeline_2d(context=self.window, sampler_type="isampler2D",
                maxval=255, yscale=-1, use_framebuffer=False, image=Texture2D(self._prepare_image(0)))
        self.current_index = 0
        self.fps = 25
        self.playing = False

    def _prepare_image(self, idx):
        img = self.images[idx]
        while img.ndim < 3:
            img = img[..., None]
        return img

    def display(self):
        self.window.clear()
        self.render_pipeline.image.data = self._prepare_image(self.current_index)
        self.window.window_title = self.images.filenames[self.current_index].filename
        self.render_pipeline.draw()
        self.window.swap_buffers()

    def keyboard(self, key, x, y):
        key = chr(key)
        if key == "+":
            self.fps *= self.fps_scale
        elif key == "-":
            self.fps /= self.fps_scale
        elif key == " ":
            if self.playing:
                self.playing = False
            else:
                self.playing = True
                self.timer()
        elif key == chr(27):
            raise SystemExit

    def special(self, key, x, y):
        if key == _gl.GLUT_KEY_LEFT:
            self.current_index = (self.current_index - 1) % len(self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_RIGHT:
            self.current_index = (self.current_index + 1) % len(self.images)
            self.window.post_redisplay()
        if key == _gl.GLUT_KEY_PAGE_UP:
            self.current_index = (self.current_index - self.fps) % len(self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_PAGE_DOWN:
            self.current_index = (self.current_index + self.fps) % len(self.images)
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_HOME:
            self.current_index = 0
            self.window.post_redisplay()
        elif key == _gl.GLUT_KEY_END:
            self.current_index = len(self.images) - 1
            self.window.post_redisplay()

    def timer(self):
        if self.playing:
            self.current_index = (self.current_index + 1) % len(self.images)
            self.window.add_timer(int(round(1000.0 / self.fps)), self.timer)
            self.window.post_redisplay()

    def run(self):
        self.timer()
        main_loop()
Example #12
0
class PointcloudRenderer(object):
    # <h3>Initialization</h3>

    # When a <code>PointcloudRenderer</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display callback function which will be defined later.
        self.window.display_callback = self.display

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # Here, we create a vertex array that contains buffers for two vertex array
        # input variables as well as an index array:
        n_points = 100000
        self.vao = VertexArray(randn(n_points, 3), randn(n_points, 3))

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()
        
        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes the
    # modelview matrix, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using <code>get_elapsed_time()</code>:
        phi = 2 * pi * get_elapsed_time() / 20.0

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), 0, sin(phi), 0), (0, 1, 0, 0), (-sin(phi), 0, cos(phi), 0), (0, 0, 0, 5))

        # The following line schedules the next timer event to execute after ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>
    
    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement:
        with self.shader:
            # The <code>State</code> class encapsulates state changes in the
            # context. For example, to enable depth testing and set the point size
            # to three for the duration of the following function call, we would
            # write:
            with State(depth_test=True, point_size=3):
                # With the shader bound, depth testing enabled, and the point size
                # set, we enter the GLUT main loop.
                main_loop()
Example #13
0
class OpenCLExample(object):
    # <h3>Initialization</h3>

    # When a <code>OpenCLExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, alpha=True, depth=True)

        # Then, we set the GLUT display and keyboard callback functions which
        # will be defined later.
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard

        # Here, we generate numpy arrays to hold the positions, colors, and
        # velocities of the particles:
        num = 200000
        positions = numpy.empty((num, 4), dtype=numpy.float32)
        colors = numpy.empty((num, 4), dtype=numpy.float32)
        velocities = numpy.empty((num, 4), dtype=numpy.float32)

        # So far, the array contents are undefined. We have to initialize them with meaningful values:
        positions[:, 0] = numpy.sin(numpy.arange(0, num) * 2 * numpy.pi / num) * (numpy.random.random_sample((num,)) / 3 + 0.2)
        positions[:, 1] = numpy.cos(numpy.arange(0, num) * 2 * numpy.pi / num) * (numpy.random.random_sample((num,)) / 3 + 0.2)
        positions[:, 2:] = 0, 1
        colors[:] = 0, 1, 0, 1
        velocities[:, :2] = 2 * positions[:, :2]
        velocities[:, 2] = 3
        velocities[:, 3] = numpy.random.random_sample((num,))

        # Instead of simply generating a vertex array from the position and color
        # data, we first generate array buffers for them:
        gl_positions = ArrayBuffer(data=positions, usage="DYNAMIC_DRAW")
        gl_colors = ArrayBuffer(data=colors, usage="DYNAMIC_DRAW")
        # These array buffers will later also be used by OpenCL. We do not need to
        # wrap <code>velocities</code> in this way, as it will only be used by
        # OpenCL and can be wrapped in an OpenCL buffer directly.

        # We now create a vertex array that will pass the position and color data
        # to the shader. The vertex array constructor accepts
        # <code>ArrayBuffer</code> instances:
        self.vao = VertexArray(gl_positions, gl_colors)

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()
        
        # Here, we create the <code>CLCode</code> object that manages OpenCL
        # interaction. It is passed the OpenGL buffer objects as well as a numpy
        # array of velocities.
        self.clcode = CLCode(gl_positions, gl_colors, velocities)

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()
        
        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback animates the
    # particle system, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first tell an instance of the <code>CLCode</code> class to execute the
        # OpenCL kernel:
        self.clcode.execute(10)

        # The following line schedules the next timer event to execute after one millisecond.
        self.window.add_timer(1, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h4>Keyboard function</h4>

    # To further illustrate the concept of GLUT callbacks, here's a keyboard
    # handler that will simply make the program exit when any key is pressed:
    def keyboard(self, key, x, y):
        raise SystemExit

    # <h3>Running</h3>
    
    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement. At
        # the same time, we can pass in additional uniform variables, such as the
        # modelview matrix:
        with self.shader(modelview_matrix=((1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0), (0, 0, 0, 2))):
            # With the shader bound, we enter the GLUT main loop.
            main_loop()
Example #14
0
class SimpleExample(object):
    # <h3>Initialization</h3>

    # When a <code>SimpleExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, multisample=True)

        # Then, we set the GLUT display callback function which will be defined
        # later.
        self.window.display_callback = self.display

        # We also set mouse callbacks that will display the pixel color in the
        # title bar.
        self.window.mouse_callback = self.mouse
        self.window.motion_callback = self.motion

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # Here, we create a vertex array that contains buffers for two vertex array
        # input variables as well as an index array:
        self.vao = VertexArray(vertices, colors, elements=indices)

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()
        
        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Mouse functions</h4>

    # The motion callback is called when the mouse is moved while a button is
    # pressed. It reads the current color of the pixel under the cursor from
    # the front buffer and displays it in the window title.
    def motion(self, x, y):
        self.window.window_title = "%.2f, %.2f, %.2f, %.2f" % tuple(self.window.front_pixels[self.window.shape[0] - y, x])

    # The mouse callback is called whenever a mouse button is pressed. It
    # redirects to the functionality of the motion callback.
    def mouse(self, button, state, x, y):
        self.motion(x, y)

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback changes the
    # modelview matrix, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first get the elapsed time from GLUT using <code>get_elapsed_time()</code>:
        phi = get_elapsed_time()

        # We then set the <code>modelview_matrix</code> uniform variable of the
        # shader created in the initialization section simply by setting an
        # attribute:
        self.shader.modelview_matrix = ((cos(phi), sin(phi), 0, 0), (-sin(phi), cos(phi), 0, 0), (0, 0, 1, 0), (0, 0, 0, 2))

        # The following line schedules the next timer event to execute after ten milliseconds.
        self.window.add_timer(10, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h3>Running</h3>
    
    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement:
        with self.shader:
            # With the shader bound, we enter the GLUT main loop.
            main_loop()
Example #15
0
class OpenCLExample(object):
    # <h3>Initialization</h3>

    # When a <code>OpenCLExample</code> instance is created, we need to
    # initialize a few OpenGL objects.
    def __init__(self):
        # First, we create a window; this also creates an OpenGL context.
        self.window = GlutWindow(double=True, alpha=True, depth=True)

        # Then, we set the GLUT display and keyboard callback functions which
        # will be defined later.
        self.window.display_callback = self.display
        self.window.keyboard_callback = self.keyboard

        # Here, we generate numpy arrays to hold the positions, colors, and
        # velocities of the particles:
        num = 200000
        positions = numpy.empty((num, 4), dtype=numpy.float32)
        colors = numpy.empty((num, 4), dtype=numpy.float32)
        velocities = numpy.empty((num, 4), dtype=numpy.float32)

        # So far, the array contents are undefined. We have to initialize them with meaningful values:
        positions[:, 0] = numpy.sin(numpy.arange(0, num) * 2 * numpy.pi /
                                    num) * (numpy.random.random_sample(
                                        (num, )) / 3 + 0.2)
        positions[:, 1] = numpy.cos(numpy.arange(0, num) * 2 * numpy.pi /
                                    num) * (numpy.random.random_sample(
                                        (num, )) / 3 + 0.2)
        positions[:, 2:] = 0, 1
        colors[:] = 0, 1, 0, 1
        velocities[:, :2] = 2 * positions[:, :2]
        velocities[:, 2] = 3
        velocities[:, 3] = numpy.random.random_sample((num, ))

        # Instead of simply generating a vertex array from the position and color
        # data, we first generate array buffers for them:
        gl_positions = ArrayBuffer(data=positions, usage="DYNAMIC_DRAW")
        gl_colors = ArrayBuffer(data=colors, usage="DYNAMIC_DRAW")
        # These array buffers will later also be used by OpenCL. We do not need to
        # wrap <code>velocities</code> in this way, as it will only be used by
        # OpenCL and can be wrapped in an OpenCL buffer directly.

        # We now create a vertex array that will pass the position and color data
        # to the shader. The vertex array constructor accepts
        # <code>ArrayBuffer</code> instances:
        self.vao = VertexArray(gl_positions, gl_colors)

        # In the OpenGL core profile, there is no such thing as a "standard pipeline"
        # any more. We use the minimalistic <code>defaultpipeline</code> from the
        # <code>glitter.convenience</code> module to create a shader program instead:
        self.shader = get_default_program()

        # Here, we create the <code>CLCode</code> object that manages OpenCL
        # interaction. It is passed the OpenGL buffer objects as well as a numpy
        # array of velocities.
        self.clcode = CLCode(gl_positions, gl_colors, velocities)

    # <h3>Callback functions</h3>

    # <h4>Display function</h4>

    # Here we define the display function. It will be called by GLUT whenever the
    # screen has to be redrawn.
    def display(self):
        # First we clear the default framebuffer:
        self.window.clear()

        # To draw the vertex array, we use:
        self.vao.draw()

        # After all rendering commands have been issued, we swap the back buffer to
        # the front, making the rendered image visible all at once:
        self.window.swap_buffers()

    # <h4>Timer function</h4>

    # The animation is controlled by a GLUT timer. The timer callback animates the
    # particle system, schedules the next timer event, and causes a screen redraw:
    def timer(self):
        # We first tell an instance of the <code>CLCode</code> class to execute the
        # OpenCL kernel:
        self.clcode.execute(10)

        # The following line schedules the next timer event to execute after one millisecond.
        self.window.add_timer(1, self.timer)

        # Finally, we tell GLUT to redraw the screen.
        self.window.post_redisplay()

    # <h4>Keyboard function</h4>

    # To further illustrate the concept of GLUT callbacks, here's a keyboard
    # handler that will simply make the program exit when any key is pressed:
    def keyboard(self, key, x, y):
        raise SystemExit

    # <h3>Running</h3>

    # We will call the <code>run()</code> method later to run the OpenGL code.
    def run(self):
        # To start the animation, we call the timer once; all subsequent timer
        # calls will be scheduled by the timer function itself.
        self.timer()

        # The default program is bound by using a <code>with</code> statement. At
        # the same time, we can pass in additional uniform variables, such as the
        # modelview matrix:
        with self.shader(modelview_matrix=((1, 0, 0, 0), (0, 0, 1, 0),
                                           (0, 1, 0, 0), (0, 0, 0, 2))):
            # With the shader bound, we enter the GLUT main loop.
            main_loop()