コード例 #1
0
    def render(self):
        if self.current_pointcloud < len(self.pointclouds):
            self.handle_mouse()
            self.handle_keys()

            self.ctx.viewport = self.wnd.viewport
            self.ctx.clear(0.0, 0.0, 0.0)
            self.ctx.enable(mgl.BLEND)

            vertices = np.load(file=self.pointclouds[self.current_pointcloud])
            self.vbo.write(vertices.astype('f4').tobytes())

            model = Matrix44.from_scale((self.zoom, self.zoom, self.zoom))
            model *= Matrix44.from_x_rotation(-self.theta[1])
            model *= Matrix44.from_y_rotation(-self.theta[0])
            view = Matrix44.look_at((0.0, 0.0, 1.0), (0.0, 0.0, 0.0),
                                    (0.0, 1.0, 0.0))
            projection = Matrix44.perspective_projection(
                45.0, self.wnd.ratio, 0.1, 100.0)

            self.mvp.write((projection * view * model).astype('f4').tobytes())
            self.vao.render(mode=mgl.POINTS)

            self.sleep_to_target_fps(60)
            self.current_pointcloud += 1
        else:
            if self.out_dir is None:
                self.current_pointcloud = 0
            else:
                QtCore.QCoreApplication.instance().quit()
コード例 #2
0
    def render(self, time, frame_time):
        self.ctx.clear(0.2, 0.2, 0.2)

        self.ctx.enable(moderngl.DEPTH_TEST)

        self.fps = 1 / frame_time
        self.control()

        proj = Matrix44.perspective_projection(45.0, self.aspect_ratio, 0.1,
                                               1000.0)
        lookat = Matrix44.look_at(
            (self.movX, self.movY, self.movZ),
            (200.0, 200.0, 0.0),
            (0.0, 0.0, 1.0),
        )

        self.light.value = (100, 0, 200)

        self.texture.use(0)
        self.mvp_map.write((proj * lookat).astype('f4'))
        self.vao_map.render(moderngl.TRIANGLE_FAN)

        model_rot = Matrix44.from_z_rotation(
            3.14 / 4) * Matrix44.from_x_rotation(-3.14 / 2)

        for x in range(int(self.positions.size / 3)):
            size = 1 + self.production[x] * (2.5 - 1)
            model_size = Matrix44.from_scale(np.array([size, size, size]))
            self.gradient.value = self.production[x]
            model = Matrix44.from_translation(np.array(
                self.positions[x])) * model_rot * model_size
            self.mvp.write((proj * lookat * model).astype('f4'))
            self.vao.render()

        self.render_ui()
コード例 #3
0
ファイル: camera.py プロジェクト: kkyong77/pyvistas
 def rotate_relative(self, rotation):
     pos = self.get_position()
     rotate_matrix = Matrix44.from_x_rotation(rotation.x) * \
                     Matrix44.from_y_rotation(rotation.y) * \
                     Matrix44.from_z_rotation(rotation.z)
     self.matrix = rotate_matrix * self.matrix
     self.set_position(pos)
コード例 #4
0
def get_rotation(x, y, z):
    logger.debug('Create rotation matrix with (x:{}, y:{}, z:{})'.format(
        x, y, z))
    x_rotation = Matrix44.from_x_rotation(x)
    y_rotation = Matrix44.from_y_rotation(y)
    z_rotation = Matrix44.from_z_rotation(z)
    return z_rotation * y_rotation * x_rotation
コード例 #5
0
def buildTransMatrix(pos=[0, 0, 0], rot=[0, 0, 0], scale=[1, 1, 1]):
    trans = Matrix44.from_translation(pos)
    rotX = Matrix44.from_x_rotation(np.radians(rot[0]))
    rotY = Matrix44.from_y_rotation(np.radians(rot[1]))
    rotZ = Matrix44.from_z_rotation(np.radians(rot[2]))
    scale = Matrix44.from_scale(scale)
    tMatrix = trans * scale * rotX * rotY * rotZ
    return tMatrix
コード例 #6
0
def applyTransforms(vector, projectionMat):
    r = time.clock() + vector[0] * 10 # rotation offset based on vector's 1st component
    rotX = Matrix44.from_x_rotation(r)
    rotY = Matrix44.from_y_rotation(r)
    rotZ = Matrix44.from_z_rotation(r)
    trans = Matrix44.from_translation(vector) * Matrix44.from_translation([1,1,-5]) # move view back by -5
    scale = Matrix44.from_scale([.5,.5,.5]) # uniformly scale by 0.5
    tMatrix = projectionMat * trans * scale * rotX * rotY * rotZ
    prog['transform'].write(tMatrix.astype('f4').tobytes())
コード例 #7
0
ファイル: 06_Camera.py プロジェクト: p3rfilov/OpenGL
def scatterCubes(vector, projectionMat):
    view = window.getViewMatrix()
    r = vector[0] * 10.0 # cube rotation offset based on vector's 1st component
    rotX = Matrix44.from_x_rotation(r*time.clock()/10.0) # rotate cubes over time
    rotY = Matrix44.from_y_rotation(r)
    rotZ = Matrix44.from_z_rotation(r)
    trans = Matrix44.from_translation(vector) * Matrix44.from_translation([1.0,1.0,-5.0])
    scale = Matrix44.from_scale([.5,.5,.5]) # uniformly scale by 0.5
    tMatrix = projectionMat * view * trans * scale * rotX * rotY * rotZ
    prog['transform'].write(tMatrix.astype('f4').tobytes())
コード例 #8
0
    def refresh_position(self):
        center = self.camera.scene.bounding_box.center
        dummy_cam = Camera()
        dummy_cam.matrix = self.default_matrix
        z_shift = dummy_cam.distance_to_point(center)
        self.camera.matrix = Matrix44.from_translation([self._shift_x, self._shift_y, self._distance]) * \
                             Matrix44.from_translation([0, 0, -z_shift]) * \
                             Matrix44.from_x_rotation(-self._angle_y) * \
                             Matrix44.from_y_rotation(-self._angle_x) * \
                             Matrix44.from_translation([0, 0, z_shift]) * \
                             self.default_matrix

        post_redisplay()
コード例 #9
0
ファイル: 04_Transformations.py プロジェクト: p3rfilov/OpenGL
def update(dt):
    proj = Matrix44.perspective_projection(50, width / height, 0.1, 1000.0)
    rotX = Matrix44.from_x_rotation(0)
    rotY = Matrix44.from_y_rotation(time.clock() * 1.5)
    rotZ = Matrix44.from_z_rotation(
        180 * np.pi / 180)  # rotate 180 degrees. Convert degrees to radians
    trans = Matrix44.from_translation(
        [np.sin(time.clock()) / 4,
         np.sin(time.clock()) / 4,
         -1.3])  # bounce diagonally from corner to corner, move back by -1.3
    scale = Matrix44.from_scale([.5, .5, .5])  # uniformly scale by 0.5
    tMatrix = proj * trans * scale * rotX * rotY * rotZ
    prog['transform'].write(tMatrix.astype('f4').tobytes())
    ctx.clear(.1, .1, .1)
    vao.render()
コード例 #10
0
    def build_matrix(self):
        """Builds and stores the transformation matrix internally"""

        m = Matrix44.identity()
        if isinstance(self.scale, list) or isinstance(self.scale, tuple):
            m.m11 = self.scale[0]
            m.m22 = self.scale[1]
            m.m33 = self.scale[2]
        else:
            m *= self.scale
            m.m44 = 1
        m = Matrix44.from_x_rotation(math.radians(self.pitch)) * m
        m = Matrix44.from_y_rotation(math.radians(self.yaw)) * m
        m = Matrix44.from_z_rotation(math.radians(self.roll)) * m
        m = Matrix44.from_translation(Vector3(self.position)) * m
        self.m = numpy.array(m).astype("f4")
コード例 #11
0
ファイル: spaceship.py プロジェクト: bogdanteleaga/TSBK07
  def getModelMatrix(self):
      scale = mat4.from_scale([0.2, 0.2, 0.2])
      
      roty = mat4.from_y_rotation(-self.hAngle)

      vdiff = self.vAngle - self.oldvAngle
      rotx = mat4.from_x_rotation(self.getxRot(vdiff))
      
      zdiff = self.hAngle - self.oldhAngle
      rotz = mat4.from_z_rotation(-self.getzRot(zdiff))

      trans = mat4.from_translation(self.position, dtype='f')
      self.oldhAngle = self.hAngle
      self.oldvAngle = self.vAngle
      
      return scale * rotz * rotx * roty * trans
コード例 #12
0
    def render(self, t):
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)

        M = np.eye(4, dtype=np.float32)
        M = M * Matrix44.from_scale((.5, .5, .5))
        M = M * Matrix44.from_translation((0, 0, -2))
        M = M * Matrix44.from_x_rotation(0)
        M = M * Matrix44.from_scale((.4, .4, .4))
        M = M * Matrix44.from_translation((0, 0, -50))

        projection = pyrr.matrix44.create_perspective_projection(
            3, 1, 0.001, 10000)
        self.tree.setProjection(projection)
        self.tree.setModelView(M)
        self.tree.render()
        gl.glDisable(gl.GL_DEPTH_TEST)
コード例 #13
0
    def build_matrix(self):
        """Builds and stores the viewport matrix internally
        Automatically builds the MVP matrix as well"""
        # Note that by nature, a camera perspective inverts everything
        # So we negate everything and also do it in reverse

        # Overrides PositionMatrix, reverse everything, ignore scale
        m = Matrix44.identity()
        m = Matrix44.from_translation(-1 * Vector3(self.position)) * m
        m = Matrix44.from_z_rotation(-math.radians(self.roll)) * m
        m = Matrix44.from_y_rotation(-math.radians(self.yaw)) * m
        m = Matrix44.from_x_rotation(-math.radians(self.pitch)) * m
        if self.tp:
            # Third person enabled
            m = Matrix44.from_translation([0, 0, -self.tp_distance]) * m

        self.m = m
        self.mvp = numpy.array(self.p * self.m).astype("f4")
コード例 #14
0
    def test_m44_q_equivalence(self):
        """Test for equivalance of matrix and quaternion rotations.

        Create a matrix and quaternion, rotate each by the same values
        then convert matrix<->quaternion and check the results are the same.
        """
        m = Matrix44.from_x_rotation(np.pi / 2.)
        mq = Quaternion.from_matrix(m)

        q = Quaternion.from_x_rotation(np.pi / 2.)
        qm = Matrix44.from_quaternion(q)

        self.assertTrue(np.allclose(np.dot([1., 0., 0., 1.], m), [1., 0., 0., 1.]))
        self.assertTrue(np.allclose(np.dot([1., 0., 0., 1.], qm), [1., 0., 0., 1.]))

        self.assertTrue(np.allclose(q * Vector4([1., 0., 0., 1.]), [1., 0., 0., 1.]))
        self.assertTrue(np.allclose(mq * Vector4([1., 0., 0., 1.]), [1., 0., 0., 1.]))

        np.testing.assert_almost_equal(np.array(q), np.array(mq), decimal=5)
        np.testing.assert_almost_equal(np.array(m), np.array(qm), decimal=5)
コード例 #15
0
    def frames():
        with create_context() as ctx:
            renderer = Renderer(ctx, (w, h), mesh, projection=projection)

            for _ in count():
                t = time.time() - beginning
                theta = t * angular_velocity
                rotation = Matrix44.from_z_rotation(
                    theta[2]) * Matrix44.from_y_rotation(
                        theta[1]) * Matrix44.from_x_rotation(theta[0])
                camera = Matrix44.from_translation(np.array([0, 0, -d
                                                             ])) * rotation
                renderer.render(camera, light1)
                buffer = np.mean(renderer.snapshot2(), axis=-1)
                lines = ascii.shade(buffer)
                text = "resolution: {w}x{h}, fov: {fov:.2f}, fps: {fps:.2f}, d: {d:.2f}, by: vidstige 2020".format(
                    w=w, h=h, fov=fov, fps=fps, d=d)
                lines[-2] = scroller(lines[-2], text, t, w=-12)
                yield b"\033[2J\033[1;1H" + b'\n'.join(lines) + b"\n"
                duration = (time.time() - beginning) - t
                if dt - duration > 0:
                    time.sleep(dt - duration)
コード例 #16
0
ファイル: ex1.py プロジェクト: nickhutchinson/SB6Python
    def render(self, app, currentTime):
        glBindVertexArray(self._vao.identifier)
        try:
            glUseProgram(self._program.identifier)

            bg_color = (
                math.sin(currentTime) * 0.5 + 0.5,
                math.cos(currentTime) * 0.5 + 0.5,
                0.0,
                1.0
            )
            glClearBufferfv(GL_COLOR, 0, bg_color)
            glClearBufferfv(GL_DEPTH, 0, [1])

            f = currentTime * 0.3
            mv_matrix = Matrix44.identity(dtype='f4')
            mv_matrix *= Matrix44.from_x_rotation(
                currentTime * math.radians(81))
            mv_matrix *= Matrix44.from_y_rotation(
                currentTime * math.radians(45))
            mv_matrix *= Matrix44.from_translation([
                math.sin(2.1 * f) * 0.5,
                math.cos(1.7 * f) * 0.5,
                math.sin(1.3 * f) * math.cos(1.5 * f) * 2.0])
            mv_matrix *= Matrix44.from_translation([0.0, 0.0, -4.0])

            self._uniform_block.mv_matrix[:] = mv_matrix.reshape(16)

            glBufferSubData(
                GL_UNIFORM_BUFFER,
                0,
                ctypes.sizeof(self._uniform_block),
                ctypes.byref(self._uniform_block))

            self._torus_obj.render()

        finally:
            glBindVertexArray(NULL_GL_OBJECT)
コード例 #17
0
    def render(self, clr_color=(1.0, 1.0, 1.0)):
        fbo = self.fbo
        fbo.clear(*clr_color)

        cam_ratio = self.fbo.size[0] / self.fbo.size[1]

        p = Matrix44.perspective_projection(self.cam_angle, cam_ratio, 0.00001,
                                            1000000.0)
        v = Matrix44.look_at(
            self.cam_pos,
            (0, 0, 0),
            self.cam_up,
        )

        rx = Matrix44.from_x_rotation(self.rotate_x)
        ry = Matrix44.from_y_rotation(self.rotate_y)
        rz = Matrix44.from_z_rotation(self.rotate_z)
        m = rx * ry * rz

        self._projection.write(p.astype('f4').tobytes())
        mv = v * m
        self._modelview.write(mv.astype('f4').tobytes())
        n = mv.inverse.transpose()
        self._normalMat.write(n.astype('f4').tobytes())
        self._mode.value = 2  # Phong
        #lightPos.value = tuple(tuple(n*Vector4.from_vector3(light_pos))[:3])
        self._lightPos.value = tuple(self.light_pos)
        self._lightColor.value = tuple(self.light_color)
        self._lightPower.value = self.light_power
        self._ambientColor.value = tuple(self.ambien_color)
        self._diffuseColor.value = tuple(self.diffuse_color)
        self._specColor.value = tuple(self.spec_color)
        self._shininess.value = self.shininess
        self._mainColor.value = tuple(self.main_color)

        self.vao.render()
        return fbo.read()
コード例 #18
0
ファイル: test_examples.py プロジェクト: spprabhu/Pyrr
    def test_operators(self):
        from pyrr import Quaternion, Matrix44, Matrix33, Vector3, Vector4
        import numpy as np

        # matrix multiplication
        m = Matrix44() * Matrix33()
        m = Matrix44() * Quaternion()
        m = Matrix33() * Quaternion()

        # matrix inverse
        m = ~Matrix44.from_x_rotation(np.pi)

        # quaternion multiplication
        q = Quaternion() * Quaternion()
        q = Quaternion() * Matrix44()
        q = Quaternion() * Matrix33()

        # quaternion inverse (conjugate)
        q = ~Quaternion()

        # quaternion dot product
        d = Quaternion() | Quaternion()

        # vector oprations
        v = Vector3() + Vector3()
        v = Vector4() - Vector4()

        # vector transform
        v = Quaternion() * Vector3()
        v = Matrix44() * Vector3()
        v = Matrix44() * Vector4()
        v = Matrix33() * Vector3()

        # dot and cross products
        dot = Vector3() | Vector3()
        cross = Vector3() ^ Vector3()
コード例 #19
0
ファイル: test_examples.py プロジェクト: RazerM/Pyrr
    def test_operators(self):
        from pyrr import Quaternion, Matrix44, Matrix33, Vector3, Vector4
        import numpy as np

        # matrix multiplication
        m = Matrix44() * Matrix33()
        m = Matrix44() * Quaternion()
        m = Matrix33() * Quaternion()

        # matrix inverse
        m = ~Matrix44.from_x_rotation(np.pi)

        # quaternion multiplication
        q = Quaternion() * Quaternion()
        q = Quaternion() * Matrix44()
        q = Quaternion() * Matrix33()

        # quaternion inverse (conjugate)
        q = ~Quaternion()

        # quaternion dot product
        d = Quaternion() | Quaternion()

        # vector oprations
        v = Vector3() + Vector3()
        v = Vector4() - Vector4()

        # vector transform
        v = Quaternion() * Vector3()
        v = Matrix44() * Vector3()
        v = Matrix44() * Vector4()
        v = Matrix33() * Vector3()

        # dot and cross products
        dot = Vector3() | Vector3()
        cross = Vector3() ^ Vector3()
コード例 #20
0
    def test_m44_q_equivalence(self):
        """Test for equivalance of matrix and quaternion rotations.

        Create a matrix and quaternion, rotate each by the same values
        then convert matrix<->quaternion and check the results are the same.
        """
        m = Matrix44.from_x_rotation(np.pi / 2.)
        mq = Quaternion.from_matrix(m)

        q = Quaternion.from_x_rotation(np.pi / 2.)
        qm = Matrix44.from_quaternion(q)

        self.assertTrue(
            np.allclose(np.dot([1., 0., 0., 1.], m), [1., 0., 0., 1.]))
        self.assertTrue(
            np.allclose(np.dot([1., 0., 0., 1.], qm), [1., 0., 0., 1.]))

        self.assertTrue(
            np.allclose(q * Vector4([1., 0., 0., 1.]), [1., 0., 0., 1.]))
        self.assertTrue(
            np.allclose(mq * Vector4([1., 0., 0., 1.]), [1., 0., 0., 1.]))

        np.testing.assert_almost_equal(q, mq, decimal=5)
        np.testing.assert_almost_equal(m, qm, decimal=5)
コード例 #21
0
 def update(self):
     center = Matrix44.from_translation(self.target)
     azim = Matrix44.from_z_rotation(self.azimuth)
     elev = Matrix44.from_x_rotation(self.elevation)
     dist = Matrix44.from_translation([0, 0, self.distance])
     self.mat_lookat = center * azim * elev * dist
コード例 #22
0
 def refresh_position(self):
     self.camera.matrix = Matrix44.from_x_rotation(self._angle_x) * \
                          Matrix44.from_y_rotation(-self._angle_y) * self.default_matrix
     post_redisplay()
コード例 #23
0
    def render(self, time, frame_time):

        # Move our camera depending on keybinds
        self.move_camera()

        # Black background, turn on depth
        self.ctx.clear(0.0, 0.0, 0.0)
        self.ctx.enable(moderngl.DEPTH_TEST)

        # Set our world scale for tessellation
        self.scale.write(np.float32(self.camera.scale).astype('f4').tobytes())  # pylint: disable=too-many-function-args

        # Put projection and look-at matrix into uniform
        self.mvp.write((self.camera.mat_projection *
                        self.camera.mat_lookat).astype('f4').tobytes())

        # Setup time, camera_position into shaders
        self.time.write(np.float32(time * 0.2).astype('f4').tobytes())  # pylint: disable=too-many-function-args
        self.camera_position.write(
            self.camera.camera_position.xy.astype('f4').tobytes())

        # Tessellate that floor!
        self.vao.render(moderngl.PATCHES)

        # ZEBRA TIME
        # Put in projection, camera position (which we call light for some reason?), and the time
        self.zmvp.write((self.camera.mat_projection *
                         self.camera.mat_lookat).astype('f4').tobytes())
        self.zlight.write((self.camera.camera_position).astype('f4').tobytes())
        self.ztime.write(np.float32(time * 0.2).astype('f4').tobytes())  # pylint: disable=too-many-function-args

        self.zuse.write(np.float32(self.zebraTime).astype('f4').tobytes())  # pylint: disable=too-many-function-args

        if not self.zebraTime:
            # Make the car look forwards properly
            wheresMyCar = Matrix44.from_translation([0, 0, -0.02])
            wheresMyCar = Matrix44.from_x_rotation(np.pi) * wheresMyCar
            wheresMyCar = Matrix44.from_z_rotation(
                (np.pi / 2) - self.camera.angle) * wheresMyCar
            # Put that movement into the shader
            self.zrotate.write((wheresMyCar).astype('f4').tobytes())

            # Set our texture, then render every part of the car with the right color
            self.car["texture"].use()
            for i in self.carDict:
                color = self.carDict[i]
                self.zcolor.write(np.array(color).astype('f4').tobytes())
                self.car[i]["vao"].render()

        else:
            # We need to get our zebra looking the right way and also slightly lower than where he starts
            rotateMyZebra = Matrix44.from_translation([0, -0.05, 0])
            rotateMyZebra = Matrix44.from_x_rotation(np.pi / 2) * rotateMyZebra
            rotateMyZebra = Matrix44.from_z_rotation(
                (np.pi / 2) - self.camera.angle) * rotateMyZebra
            # Put that movement into the shader
            self.zrotate.write((rotateMyZebra).astype('f4').tobytes())

            # Show us the zebra!
            self.texture.use()
            self.vao2.render()
コード例 #24
0
 def rotate_x(self, angle):
     self._rotation *= Matrix44.from_x_rotation(angle)
     self._update_uniforms()
コード例 #25
0
 def get_rotation_matrix(self):
     self._module_thetas()
     return Matrix44.from_x_rotation(self._x_rotate_theta) \
         * Matrix44.from_y_rotation(self._y_rotate_theta) \
         * Matrix44.from_z_rotation(self._z_rotate_theta)
コード例 #26
0
ファイル: mesh.py プロジェクト: ywcmaike/simple-3dviz
 def rotate_x(self, angle):
     """Helper function that multiplies the `model_matrix` with a rotation
     matrix around the x axis."""
     m = Matrix44.from_x_rotation(angle)
     self.model_matrix = m.dot(self.model_matrix)
コード例 #27
0
def main():
    glfw.init()
    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)

    window = glfw.create_window(width, height, "LearnOpenGL", None, None)
    if not window:
        print("Window Creation failed!")
        glfw.terminate()

    glfw.make_context_current(window)
    glfw.set_window_size_callback(window, on_resize)

    gl.glEnable(gl.GL_DEPTH_TEST)
    shader = Shader(CURDIR / 'shaders/6.1.coordinate_systems.vs',
                    CURDIR / 'shaders/6.1.coordinate_systems.fs')

    vertices = [
        # positions      tex_coords
        -0.5,
        -0.5,
        -0.5,
        0.0,
        0.0,
        0.5,
        -0.5,
        -0.5,
        1.0,
        0.0,
        0.5,
        0.5,
        -0.5,
        1.0,
        1.0,
        0.5,
        0.5,
        -0.5,
        1.0,
        1.0,
        -0.5,
        0.5,
        -0.5,
        0.0,
        1.0,
        -0.5,
        -0.5,
        -0.5,
        0.0,
        0.0,
        -0.5,
        -0.5,
        0.5,
        0.0,
        0.0,
        0.5,
        -0.5,
        0.5,
        1.0,
        0.0,
        0.5,
        0.5,
        0.5,
        1.0,
        1.0,
        0.5,
        0.5,
        0.5,
        1.0,
        1.0,
        -0.5,
        0.5,
        0.5,
        0.0,
        1.0,
        -0.5,
        -0.5,
        0.5,
        0.0,
        0.0,
        -0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        -0.5,
        0.5,
        -0.5,
        1.0,
        1.0,
        -0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        -0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        -0.5,
        -0.5,
        0.5,
        0.0,
        0.0,
        -0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        0.5,
        0.5,
        -0.5,
        1.0,
        1.0,
        0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        0.5,
        -0.5,
        0.5,
        0.0,
        0.0,
        0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        -0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        0.5,
        -0.5,
        -0.5,
        1.0,
        1.0,
        0.5,
        -0.5,
        0.5,
        1.0,
        0.0,
        0.5,
        -0.5,
        0.5,
        1.0,
        0.0,
        -0.5,
        -0.5,
        0.5,
        0.0,
        0.0,
        -0.5,
        -0.5,
        -0.5,
        0.0,
        1.0,
        -0.5,
        0.5,
        -0.5,
        0.0,
        1.0,
        0.5,
        0.5,
        -0.5,
        1.0,
        1.0,
        0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        0.5,
        0.5,
        0.5,
        1.0,
        0.0,
        -0.5,
        0.5,
        0.5,
        0.0,
        0.0,
        -0.5,
        0.5,
        -0.5,
        0.0,
        1.0
    ]
    vertices = (c_float * len(vertices))(*vertices)

    vao = gl.glGenVertexArrays(1)
    gl.glBindVertexArray(vao)

    vbo = gl.glGenBuffers(1)
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
    gl.glBufferData(gl.GL_ARRAY_BUFFER, sizeof(vertices), vertices,
                    gl.GL_STATIC_DRAW)

    gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE,
                             5 * sizeof(c_float), c_void_p(0))
    gl.glEnableVertexAttribArray(0)

    gl.glVertexAttribPointer(1, 2, gl.GL_FLOAT,
                             gl.GL_FALSE, 5 * sizeof(c_float),
                             c_void_p(3 * sizeof(c_float)))
    gl.glEnableVertexAttribArray(1)

    # -- load texture 1
    texture1 = gl.glGenTextures(1)
    gl.glBindTexture(gl.GL_TEXTURE_2D, texture1)
    # -- texture wrapping
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT)
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT)
    # -- texture filterting
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)

    img = Image.open(Tex('container.jpg')).transpose(Image.FLIP_TOP_BOTTOM)
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, img.width, img.height, 0,
                    gl.GL_RGB, gl.GL_UNSIGNED_BYTE, img.tobytes())
    gl.glGenerateMipmap(gl.GL_TEXTURE_2D)

    # -- load texture 2
    texture2 = gl.glGenTextures(1)
    gl.glBindTexture(gl.GL_TEXTURE_2D, texture2)
    # -- texture wrapping
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT)
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT)
    # -- texture filterting
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
    gl.glTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)

    img = Image.open(Tex('awesomeface.png')).transpose(Image.FLIP_TOP_BOTTOM)
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, img.width, img.height, 0,
                    gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, img.tobytes())
    gl.glGenerateMipmap(gl.GL_TEXTURE_2D)

    shader.use()
    shader.set_int("texture1", 0)
    shader.set_int("texture2", 1)

    while not glfw.window_should_close(window):
        process_input(window)

        gl.glClearColor(.2, .3, .3, 1.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_2D, texture1)
        gl.glActiveTexture(gl.GL_TEXTURE1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, texture2)

        shader.use()
        model = Matrix44.from_x_rotation(
            glfw.get_time() * 0.5) * Matrix44.from_y_rotation(glfw.get_time())
        view = Matrix44.from_translation([0, 0, -3])
        projection = Matrix44.perspective_projection(45, width / height, 0.1,
                                                     100.0)

        shader.set_mat4('view', view)
        shader.set_mat4('model', model)
        shader.set_mat4('projection', projection)
        gl.glBindVertexArray(vao)
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 36)

        glfw.poll_events()
        glfw.swap_buffers(window)

    gl.glDeleteVertexArrays(1, id(vao))
    gl.glDeleteBuffers(1, id(vbo))
    glfw.terminate()