Python SDL2 TTF test

For cross platform windowing, input, font rendering and probably the entire 2d gui render of the engine, I have decided to use PySDL2, since I had some troubles with SFML (crashes in debug mode in PyCharm).

Next is an almost direct conversion from C to Python of the example found here:

The Glametrix font I used comes from here:

I placed the SDL2 and SDL2_ttf libraries in the script’s folder, inside another folder called ‘libs’ and the font in a folder called ‘font’.




import os
from sys import exit
from ctypes import c_long, pointer

sdlpath = os.path.join(os.path.dirname(__file__), 'libs')
os.environ['PYSDL2_DLL_PATH'] = sdlpath

from sdl2 import *
from sdl2.sdlttf import *

def renderTexture(tex, ren, x, y):
    :type ren: SDL_Renderer
    :type tex: SDL_Texture

    #Setup the destination rectangle to be at the position we want
    dst = SDL_Rect(x, y)
    w = pointer(c_long(0))
    h = pointer(c_long(0))
    #Query the texture to get its width and height to use
    SDL_QueryTexture(tex, None, None, w, h)
    dst.w = w.contents.value
    dst.h = h.contents.value
    SDL_RenderCopy(ren, tex, None, dst)

def renderText(message, fontFile, color, fontSize, renderer):

    :rtype : SDL_Texture
    # Open the font
    font = TTF_OpenFont(fontFile, fontSize)
    p = SDL_GetError()
    if font is None or not p == '':
        print("TTF_OpenFont error: " + p)
        return None

    #We need to first render to a surface as that's what TTF_RenderText
    #returns, then load that surface into a texture
    surf = TTF_RenderText_Blended(font, message, color)

    if surf is None:
        return None

    texture = SDL_CreateTextureFromSurface(renderer, surf)
    if texture is None:

    #Clean up the surface and font
    return texture

#Create an application window with the following settings:
window = SDL_CreateWindow(
    "SDL2 TTF test",  # window title
    SDL_WINDOWPOS_CENTERED,  # initial x position
    SDL_WINDOWPOS_CENTERED,  # initial y position
    640,  # width, in pixels
    480,  # height, in pixels

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)

tfi = TTF_Init()
if tfi != 0:

#We'll render the string "TTF fonts are cool!" in white
#Color is in RGB format
color = SDL_Color(255, 255, 255)
fontpath = os.path.join(os.path.dirname(__file__), 'font', 'Glametrix.otf')
image = renderText("TTF fonts are cool!", fontpath,
                   color, 64, renderer)

if image is None:

#Getting the window size.
SCREEN_WIDTH = pointer(c_long(0))
SCREEN_HEIGHT = pointer(c_long(0))

#Get the texture w/h so we can center it in the screen
iW = pointer(c_long(0))
iH = pointer(c_long(0))
SDL_QueryTexture(image, None, None, iW, iH)
x = SCREEN_WIDTH.contents.value / 2 - iW.contents.value / 2
y = SCREEN_HEIGHT.contents.value / 2 - iH.contents.value / 2

r = 1
event = SDL_Event()
while r:
    if SDL_PollEvent(event):
        if event.type == SDL_QUIT:
            r = 0
        elif event.type == SDL_WINDOWEVENT:
            if event.window.event == SDL_WINDOWEVENT_RESIZED:
                SDL_GetWindowSize(window, SCREEN_WIDTH, SCREEN_HEIGHT)
                x = SCREEN_WIDTH.contents.value / 2 - iW.contents.value / 2
                y = SCREEN_HEIGHT.contents.value / 2 - iH.contents.value / 2
        if r:
            #We can draw our message as we do any other texture, since it's been
            #rendered to a texture
            renderTexture(image, renderer, x, y)


I moved the drawing stuff to the event processing so the text is drawn only if there is a change (window re-paint, resize).

PS: Somebody knows a way to avoid using ctypes pointers in the few PySDL2 functions that need them?


2 thoughts on “Python SDL2 TTF test

  1. Thankyou so much – I spent hours looking for a simple, working example – This really helped me out. I’d like to attribute you in the source, but can’t seem to see your name?

    1. Hi. Thanks fro the comment. Although I doubt attributing a piece of code so generic would be necessary, a link to this blog entry is enough for me in tis case. Thank you.

Comments are closed.