Пример #1
0
        glDebugMessageCallback(GLDEBUGPROC(debug_message_callback), None)
    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    glfw.set_scroll_callback(theWindow, window_scroll_callback)

    vbo = VBO(vertices, 'GL_STATIC_DRAW')
    vbo.create_buffers()

    vao = glGenVertexArrays(1)
    glBindVertexArray(vao)
    vbo.bind()
    vbo.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    glBindVertexArray(0)

    # compile program
    renderProgram = GLProgram(rayTracingVertexShaderSource, rayTracingFragmentShaderSource)
    renderProgram.compile_and_link()
    uniformInfos = [
        ('backColor', 'vec3f'),
        ('ambientColor', 'vec3f'),
Пример #2
0
        glDebugMessageCallback(GLDEBUGPROC(debug_message_callback), None)
    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    glfw.set_scroll_callback(theWindow, window_scroll_callback)

    sphereDataVBO = VBO(sphereData, usage='GL_STATIC_DRAW')
    sphereDataVBO.create_buffers()

    sphereVAO = glGenVertexArrays(1)

    glBindVertexArray(sphereVAO)
    sphereDataVBO.bind()
    sphereDataVBO.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT,
                          GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float),
                          ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
                          6 * ctypes.sizeof(ctypes.c_float),
                          ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float)))
    glEnableVertexAttribArray(1)
    sphereDataVBO.unbind()
Пример #3
0
                                   'Hello Triangle', None, None)
    # make window the current context
    glfw.make_context_current(theWindow)

    if platform.system().lower() != 'darwin':
        # enable debug output
        # doesn't seem to work on macOS
        glEnable(GL_DEBUG_OUTPUT)
        glDebugMessageCallback(GLDEBUGPROC(debug_message_callback), None)

    # set resizing callback function
    glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    # create VBO to store vertices
    verticesVBO = VBO(triangleVertices, usage='GL_STATIC_DRAW')
    verticesVBO.create_buffers()

    # create VAO to describe array information
    triangleVAO = glGenVertexArrays(1)

    # bind VAO
    glBindVertexArray(triangleVAO)

    # bind VBO
    verticesVBO.bind()
    # buffer data into OpenGL
    verticesVBO.copy_data()

    # configure the fist 3-vector (pos)
    # arguments: index, size, type, normalized, stride, pointer
    # the stride is 6 * 4 because there are six floats per vertex, and the size of
Пример #4
0
        glDebugMessageCallback(GLDEBUGPROC(debug_message_callback), None)
    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    glfw.set_scroll_callback(theWindow, window_scroll_callback)

    vertexVBO = VBO(vertices, usage='GL_STATIC_DRAW')
    vertexVBO.create_buffers()
    textureVBO = VBO(textureVertices, usage='GL_STATIC_DRAW')
    textureVBO.create_buffers()

    frameVAO = glGenVertexArrays(1)
    glBindVertexArray(frameVAO)
    vertexVBO.bind()
    vertexVBO.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT,
                          GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float),
                          ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    glBindVertexArray(0)

    textureVAO = glGenVertexArrays(1)
    glBindVertexArray(textureVAO)
Пример #5
0
    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    glfw.set_scroll_callback(theWindow, window_scroll_callback)

    # create VBOs to store vertices, normals and elements
    cubeDataVBO = VBO(cubeData, usage='GL_STATIC_DRAW')
    cubeDataVBO.create_buffers()

    sphereDataVBO = VBO(sphereData, usage='GL_STATIC_DRAW')
    sphereDataVBO.create_buffers()

    # create VAO to describe array information
    triangleVAO, sphereVAO = glGenVertexArrays(2)

    # bind VAO
    glBindVertexArray(triangleVAO)
    # bind data VBO
    cubeDataVBO.bind()
    cubeDataVBO.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT,
                          GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float),
                          ctypes.c_void_p(0))
def image_server(evtQueue, resultQueue):

    # resource-taking objects
    resObjs = []

    # initialize glfw
    glfw.init()

    # set glfw config
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
    glfw.window_hint(glfw.RESIZABLE, GL_FALSE)

    if pyPlatform.system().lower() == 'darwin':
        glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)

    # create window
    theWindow = glfw.create_window(windowSize[0], windowSize[1], 'Spherical Projection', None, None)
    # make window the current context
    glfw.make_context_current(theWindow)


    # enable z-buffer
    glEnable(GL_DEPTH_TEST)

    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    #glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    #glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    #glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    # glfw.set_scroll_callback(theWindow, window_scroll_callback)

    vbo = VBO(vertices, 'GL_STATIC_DRAW')
    vbo.create_buffers()
    resObjs.append(vbo)

    vao = glGenVertexArrays(1)
    glBindVertexArray(vao)
    vbo.bind()
    vbo.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    glBindVertexArray(0)

    # compile program
    renderProgram = GLProgram(rayTracingVertexShaderSource, rayTracingFragmentShaderSource)
    renderProgram.compile_and_link()
    uniformInfos = [
        ('backColor', 'vec3f'),
        ('ambientColor', 'vec3f'),
        ('o_c', 'vec3f'),
        ('o_p', 'vec3f'),
        ('x_c', 'vec3f'),
        ('y_c', 'vec3f'),
        ('x_p', 'vec3f'),
        ('y_p', 'vec3f'),
        ('c_c', 'vec3f'),
        ('c_p', 'vec3f'),
        ('winSize', 'vec2f')
    ]
    uniforms = create_uniform(renderProgram.get_program_id(), uniformInfos)


    # keep rendering until the window should be closed
    while not glfw.window_should_close(theWindow):

        # set background color
        glClearColor(*windowBackgroundColor)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        renderProgram.use()

        # update uniforms
        o_c, c_c, x_c, y_c = get_camera_vectors(camera)
        o_p, c_p, x_p, y_p = get_camera_vectors(projector)
        uniforms['o_c'].update(o_c)
        uniforms['x_c'].update(x_c)
        uniforms['y_c'].update(y_c)
        uniforms['c_c'].update(c_c)

        uniforms['o_p'].update(o_p)
        uniforms['x_p'].update(x_p)
        uniforms['y_p'].update(y_p)
        uniforms['c_p'].update(c_p)
        uniforms['backColor'].update(backColor)
        uniforms['ambientColor'].update(ambientColor)
        uniforms['winSize'].update(windowSize.astype(np.float32))

        try:
            newImage = evtQueue.get(timeout=0.05)
        except Exception as e:
            # tell glfw to poll and process window events
            glfw.poll_events()
            # swap frame buffer
            glfw.swap_buffers(theWindow)
            continue

        texture = create_texture(newImage)

        glBindVertexArray(vao)
        glActiveTexture(GL_TEXTURE0)
        texture.bind()
        glDrawArrays(GL_TRIANGLES, 0, 6)
        texture.unbind()
        glBindVertexArray(0)

        texture.delete()

        # respond key press
        keyboard_respond_func()
        # tell glfw to poll and process window events
        glfw.poll_events()
        # swap frame buffer
        glfw.swap_buffers(theWindow)

        result = get_screenshot(windowSize)
        resultQueue.put(result)

    for obj in resObjs:
        obj.delete()

    # terminate glfw
    glfw.terminate()
Пример #7
0
        glDebugMessageCallback(GLDEBUGPROC(debug_message_callback), None)
    # set resizing callback function
    # glfw.set_framebuffer_size_callback(theWindow, window_resize_callback)

    glfw.set_key_callback(theWindow, window_keypress_callback)
    # disable cursor
    glfw.set_input_mode(theWindow, glfw.CURSOR, glfw.CURSOR_DISABLED)

    glfw.set_cursor_pos_callback(theWindow, window_cursor_callback)
    # initialize cursor position
    cursorPos = glfw.get_cursor_pos(theWindow)

    glfw.set_scroll_callback(theWindow, window_scroll_callback)

    gridVBO = VBO(gridArray, usage='GL_DYNAMIC_DRAW')
    gridVBO.create_buffers()
    gridEBO = VBO(elementArray,
                  usage='GL_STATIC_DRAW',
                  target='GL_ELEMENT_ARRAY_BUFFER')
    gridEBO.create_buffers()

    gridVAO = glGenVertexArrays(1)

    glBindVertexArray(gridVAO)
    gridVBO.bind()
    gridVBO.copy_data()
    gridEBO.bind()
    gridEBO.copy_data()
    glVertexAttribPointer(0, 3, GL_FLOAT,
                          GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float),
                          ctypes.c_void_p(0))
Пример #8
0
class TextDrawer:
    def __init__(self):
        self.face = None
        self.textures = dict()

        # compile rendering program
        self.renderProgram = GLProgram(_textVertexShaderSource,
                                       _textFragmentShaderSource)
        self.renderProgram.compile_and_link()

        # make projection uniform
        self.projectionUniform = GLUniform(self.renderProgram.get_program_id(),
                                           'projection', 'mat4f')
        self.textColorUniform = GLUniform(self.renderProgram.get_program_id(),
                                          'textColor', 'vec3f')
        self.textureSizeUniform = GLUniform(
            self.renderProgram.get_program_id(), 'textureSize', 'vec2f')

        # create rendering buffer
        self.vbo = VBO(_get_rendering_buffer(0, 0, 0, 0))
        self.vbo.create_buffers()
        self.vboId = glGenBuffers(1)

        # initialize VAO
        self.vao = glGenVertexArrays(1)
        glBindVertexArray(self.vao)
        glBindBuffer(GL_ARRAY_BUFFER, self.vboId)
        self.vbo.bind()
        self.vbo.copy_data()
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
                              5 * ctypes.sizeof(ctypes.c_float),
                              ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(
            1, 2, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float),
            ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float)))
        glEnableVertexAttribArray(1)
        # self.vbo.unbind()
        glBindVertexArray(0)

        self.zNear = -1.0
        self.zFar = 1.0

    def delete(self):
        self.textures.clear()
        self.face = None
        self.renderProgram.delete()
        self.projectionUniform = None
        self.textColorUniform = None
        self.textureSizeUniform = None
        self.vbo.delete()
        glDeleteVertexArrays(1, [self.vao])

    def load_font(self, fontFilename, fontSize):
        assert os.path.exists(fontFilename)
        self.textures.clear()

        self.face = ft.Face(fontFilename)
        self.face.set_char_size(fontSize)

        # load all ASCII characters
        for i in range(128):
            self.load_character(chr(i))

    def load_character(self, character):
        assert self.face is not None
        assert len(character) == 1

        if character not in self.textures:
            # load glyph in freetype
            self.face.load_char(character)
            ftBitmap = self.face.glyph.bitmap
            height, width = ftBitmap.rows, ftBitmap.width
            bitmap = np.array(ftBitmap.buffer, dtype=np.uint8).reshape(
                (height, width))

            # create texture
            texture = _create_text_texture(bitmap)

            # add texture object to the dictionary
            characterSlot = CharacterSlot(texture, self.face.glyph)
            self.textures[character] = characterSlot

    def get_character(self, ch):
        if ch not in self.textures:
            self.load_character(ch)
        return self.textures[ch]

    def _draw_text(self, text, textPos, windowSize, scale, linespread,
                   foreColor):
        if len(text) == 0:
            return

        blendEnabled = glIsEnabled(GL_BLEND)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        self.renderProgram.use()
        glBindVertexArray(self.vao)
        glActiveTexture(GL_TEXTURE0)

        foreColor = np.asarray(foreColor, np.float32)
        self.textColorUniform.update(foreColor)

        projectionMat = orthographic_projection(0.0, windowSize[0], 0.0,
                                                windowSize[1], self.zNear,
                                                self.zFar)
        self.projectionUniform.update(projectionMat)

        lineY = textPos[1]
        nowX = textPos[0]

        # split text into lines
        lines = text.split('\n')

        for line in lines:

            if len(line) > 0:
                # analyze this line
                bearings = []
                for ch in line:
                    charSlot = self.get_character(ch)
                    bearings.append(charSlot.bearing[1] * scale[1])

                maxBearings = max(bearings)

                for ch in line:
                    charSlot = self.get_character(ch)

                    xpos = nowX + charSlot.bearing[0] * scale[0]
                    yLowerd = (maxBearings - charSlot.bearing[1] * scale[1])
                    ypos = lineY - yLowerd

                    w = charSlot.textureSize[0] * scale[0]
                    h = charSlot.textureSize[1] * scale[1]

                    self.textureSizeUniform.update(np.array((w, h),
                                                            np.float32))
                    charSlot.texture.bind()
                    self.vbo.bind()
                    self.vbo.set_array(
                        _get_rendering_buffer(xpos, ypos, w, h, 0.999))
                    self.vbo.copy_data()
                    self.vbo.unbind()

                    glDrawArrays(GL_TRIANGLES, 0, 6)
                    charSlot.texture.unbind()

                    # the advance is number of 1/64 pixels
                    nowX += (charSlot.advance / 64.0) * scale[0]

            nowX = textPos[0]

            yOffset = self.get_character(
                'X').textureSize[1] * scale[1] * linespread
            lineY -= yOffset

        glBindVertexArray(0)

        if not blendEnabled:
            glDisable(GL_BLEND)

    def draw_text(self,
                  text,
                  textPos,
                  windowSize,
                  color=(1.0, 1.0, 1.0),
                  scale=(1.0, 1.0),
                  linespread=1.5):
        return self._draw_text(text, textPos, windowSize, scale, linespread,
                               color)
Пример #9
0
class TextDrawer_Outlined:
    def __init__(self):
        self.face = None
        self.stroker = None
        self.foreTextures = dict()
        self.backTextures = dict()

        # compile rendering program
        self.renderProgram = GLProgram(_textVertexShaderSource,
                                       _textFragmentShaderSource)
        self.renderProgram.compile_and_link()

        # make projection uniform
        self.projectionUniform = GLUniform(self.renderProgram.get_program_id(),
                                           'projection', 'mat4f')
        self.textColorUniform = GLUniform(self.renderProgram.get_program_id(),
                                          'textColor', 'vec3f')
        self.textureSizeUniform = GLUniform(
            self.renderProgram.get_program_id(), 'textureSize', 'vec2f')

        # create rendering buffer
        self.vbo = VBO(_get_rendering_buffer(0, 0, 0, 0))
        self.vbo.create_buffers()
        self.vboId = glGenBuffers(1)

        # initialize VAO
        self.vao = glGenVertexArrays(1)
        glBindVertexArray(self.vao)
        glBindBuffer(GL_ARRAY_BUFFER, self.vboId)
        self.vbo.bind()
        self.vbo.copy_data()
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
                              5 * ctypes.sizeof(ctypes.c_float),
                              ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(
            1, 2, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float),
            ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float)))
        glEnableVertexAttribArray(1)
        # self.vbo.unbind()
        glBindVertexArray(0)

        self.zNear = -1.0
        self.zFar = 1.0

    def delete(self):
        self.foreTextures.clear()
        self.backTextures.clear()
        self.face = None
        self.stroker = None
        self.renderProgram.delete()
        self.projectionUniform = None
        self.textColorUniform = None
        self.textureSizeUniform = None
        self.vbo.delete()
        glDeleteVertexArrays(1, [self.vao])

    def load_font(self, fontFilename, fontSize, outlineSize=2 * 64):
        assert os.path.exists(fontFilename)
        self.foreTextures.clear()
        self.backTextures.clear()

        self.face = ft.Face(fontFilename)
        self.face.set_char_size(fontSize)

        self.outlineSize = outlineSize
        self.stroker = ft.Stroker()
        self.stroker.set(outlineSize,
                         ft.FT_STROKER_LINECAPS['FT_STROKER_LINECAP_ROUND'],
                         ft.FT_STROKER_LINEJOINS['FT_STROKER_LINEJOIN_ROUND'],
                         0)

        # load all ASCII characters
        for i in range(128):
            self.load_character(chr(i))

    def load_character(self, character):
        assert self.face is not None
        assert len(character) == 1

        if character not in self.foreTextures:
            # load background glyph
            # the render option will lead to an outline glyph (not rendered)
            self.face.load_char(character, ft.FT_LOAD_FLAGS['FT_LOAD_DEFAULT'])
            backGlyph = ft.FT_Glyph()
            ft.FT_Get_Glyph(self.face.glyph._FT_GlyphSlot, ft.byref(backGlyph))
            backGlyph = ft.Glyph(backGlyph)
            # add border to the glyph
            error = ft.FT_Glyph_StrokeBorder(ft.byref(backGlyph._FT_Glyph),
                                             self.stroker._FT_Stroker, False,
                                             False)
            if error:
                raise ft.FT_Exception(error)

            # the render option will lead to a rendered glyph
            backBitmapGlyph = backGlyph.to_bitmap(
                ft.FT_RENDER_MODES['FT_RENDER_MODE_NORMAL'], 0)

            backBitmap = backBitmapGlyph.bitmap
            backHeight, backWidth = backBitmap.rows, backBitmap.width
            backBitmap = np.array(backBitmap.buffer, dtype=np.uint8).reshape(
                (backHeight, backWidth))

            backTexture = _create_text_texture(backBitmap)

            backSlot = CharacterSlot(backTexture, backBitmapGlyph)
            self.backTextures[character] = backSlot

            # load foreground glyph
            self.face.load_char(character, ft.FT_LOAD_FLAGS['FT_LOAD_RENDER'])
            foreBitmap = self.face.glyph.bitmap
            foreHeight, foreWidth = foreBitmap.rows, foreBitmap.width
            foreBitmap = np.array(foreBitmap.buffer, dtype=np.uint8).reshape(
                (foreHeight, foreWidth))

            foreTexture = _create_text_texture(foreBitmap)

            foreSlot = CharacterSlot(foreTexture, self.face.glyph)
            self.foreTextures[character] = foreSlot

    def get_character(self, ch):
        if ch not in self.foreTextures:
            self.load_character(ch)
        return (self.foreTextures[ch], self.backTextures[ch])

    def _draw_text(self, text, textPos, windowSize, scale, linespread,
                   foreColor, backColor):
        if len(text) == 0:
            return

        blendEnabled = glIsEnabled(GL_BLEND)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        self.renderProgram.use()
        glBindVertexArray(self.vao)
        glActiveTexture(GL_TEXTURE0)

        foreColor = np.asarray(foreColor, np.float32)
        backColor = np.asarray(backColor, np.float32)

        projectionMat = orthographic_projection(0.0, windowSize[0], 0.0,
                                                windowSize[1], self.zNear,
                                                self.zFar)
        self.projectionUniform.update(projectionMat)

        lineY = textPos[1]
        nowX = textPos[0]

        # split text into lines
        lines = text.split('\n')

        for line in lines:

            if len(line) > 0:
                # analyze this line
                bearings = []
                for ch in line:
                    _, backSlot = self.get_character(ch)
                    bearings.append(backSlot.bearing)

                minBearings_X = min(zip(*bearings),
                                    key=operator.itemgetter(0))[0] * scale[0]
                maxBearings_Y = max(zip(*bearings),
                                    key=operator.itemgetter(1))[1] * scale[1]
                nowX = -minBearings_X

                for ch in line:
                    foreSlot, backSlot = self.get_character(ch)

                    # draw the background
                    xpos = nowX + backSlot.bearing[0] * scale[0]
                    yLowerd = (maxBearings_Y - backSlot.bearing[1] * scale[1])
                    ypos = lineY - yLowerd

                    w = backSlot.textureSize[0] * scale[0]
                    h = backSlot.textureSize[1] * scale[1]

                    self.textureSizeUniform.update(np.array((w, h),
                                                            np.float32))
                    backSlot.texture.bind()
                    self.textColorUniform.update(backColor)
                    self.vbo.bind()
                    self.vbo.set_array(
                        _get_rendering_buffer(xpos, ypos, w, h, 0.99))
                    self.vbo.copy_data()
                    self.vbo.unbind()
                    glDrawArrays(GL_TRIANGLES, 0, 6)
                    backSlot.texture.unbind()

                    # draw the foreground
                    xpos = nowX + foreSlot.bearing[0] * scale[0]
                    yLowerd = (maxBearings_Y - foreSlot.bearing[1] * scale[1])
                    ypos = lineY - yLowerd

                    w = foreSlot.textureSize[0] * scale[0]
                    h = foreSlot.textureSize[1] * scale[1]

                    foreSlot.texture.bind()
                    self.textColorUniform.update(foreColor)
                    self.vbo.bind()
                    # the foreground is set closer to the screen so that it
                    # is rendered above the background
                    self.vbo.set_array(
                        _get_rendering_buffer(xpos, ypos, w, h, 0.999))
                    self.vbo.copy_data()
                    self.vbo.unbind()
                    glDrawArrays(GL_TRIANGLES, 0, 6)
                    foreSlot.texture.unbind()

                    # the advance is number of 1/64 pixels
                    nowX += ((foreSlot.advance + 2.0 * self.outlineSize) /
                             64.0) * scale[0]

            yOffset = self.get_character(
                'X')[1].textureSize[1] * scale[1] * linespread
            lineY -= yOffset

        glBindVertexArray(0)

        if not blendEnabled:
            glDisable(GL_BLEND)

    def draw_text(self,
                  text,
                  textPos,
                  windowSize,
                  foreColor=(1.0, 1.0, 1.0),
                  backColor=(0.0, 0.0, 0.0),
                  scale=(1.0, 1.0),
                  linespread=1.5):
        return self._draw_text(text, textPos, windowSize, scale, linespread,
                               foreColor, backColor)