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:

http://www.willusher.io/sdl2%20tutorials/2013/12/18/lesson-6-true-type-fonts-with-sdl_ttf/

The Glametrix font I used comes from here:

http://www.glukfonts.pl/font.php?font=Glametrix

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’.

Result:

sdlTTF

Code:

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
    SDL_ClearError()
    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:
        TTF_CloseFont(font)
        print("TTF_RenderText")
        return None

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

    #Clean up the surface and font
    SDL_FreeSurface(surf)
    TTF_CloseFont(font)
    return texture

SDL_Init(SDL_INIT_VIDEO)
#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
    SDL_WINDOW_RESIZABLE  # flags
)

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)

tfi = TTF_Init()
if tfi != 0:
    print("TTF_Init")
    exit(1)

#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:
    exit(1)

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

#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:
            SDL_RenderClear(renderer)
            #We can draw our message as we do any other texture, since it's been
            #rendered to a texture
            renderTexture(image, renderer, x, y)
            SDL_RenderPresent(renderer)

SDL_DestroyTexture(image)
SDL_DestroyRenderer(renderer)
SDL_DestroyWindow(window)
SDL_Quit()

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?

Advertisements

The march to the Penguin [Switching to Linux]

[Edit: removed stuff to go straight to the point]

My history with Linux has never been of success, because I had never been able to run a single ‘distro’ in none of my computers (all of them gone now, except the last [the Big] one), until very recently:

  • On Pentium 1 – Fail (none ran at all)
  • On Celeron D – Fail (only one entered to the desktop and froze there)
  • On Core2Duo – Fail (only Ubuntu entered to the desktop, and froze there)

Unfortunately I don’t remember the names of the versions I tried in the past, except Ubuntu. Anyway, this time I had a new and shiny graphics card that should at least solve the error I got the last time about my card not being capable of handling Unity desktop effects (on Ubuntu 10).

So, what requirements should I consider when searching for a Linux version? At the end it was very simple:

  1. Decent performance and compatibility in my two computers (yes, I’m poor but I managed to have two. Isn’t it great?!)
  2. Plenty of ‘apps’ in the repository (I don’t want to spend time compiling)
  3. Ease of use for a ‘noob’
  4. Modern look in the desktop (skinned, non flat nor squared controls, effects)
  5. 32 bits version (for the laptop)

Since the beginning I knew that one distro was already ahead of the others, simple because it is backed by a big company: Ubuntu, by Canonical.

But I am trying to escape from certain things that this company represents very well (and I didn’t liked Ubuntu desktop last time), so I started testing distributions. Specifically, this list made the testing process very easy and well informed:

http://www.techradar.com/news/software/operating-systems/best-linux-distro-five-we-recommend-1090058

Results in order:

DSL: Too much simple look. Hard to use for newcomers. Fast. Only works in the laptop.

Slax: Great. The main reason I kept trying. I would keep it, but only runs on the laptop.

Chakra: Discarded. Only 64 bits (But really wanted to try it).

Debian: It never installed under Virtualbox, so I didn’t tried it more.

Mageia: Great feeling. But runs to slow in the laptop, and the available software is too few.

Manjaro: The second best. Gives me a great feeling and runs very fast in the Big one. Won’t run in the laptop (froze in the desktop).

Sabayon: Decent speed in the laptop. Does not run in the Big one (again, froze in the desktop).

Kubuntu: Since I liked the K-desktop, I tried this Ubuntu version. It ended up being perfect for me, and runs in both computers. With the Debian-like repositories available. But is from Canonical!

OpenSuse: Never finished downloading.

Kanotix | Knoppix: Before those ended downloading, I decided to stop testing.

I’m sure that the problems I had with the other Linux versions can be fixed, but I just need something to start working.  So now I’m Using Kubuntu. And even with the big list of software available for it, I have ended compiling stuff anyway, but it probed to be easy enough, yet, not fast.at all.

compiling oxygenKubuntu_oxygen

(Me compiling Oxygen Transparent, the first thing I compiled under my first Linux installation)

PyOpenGL performance 2 and optimizations

Premature optimization is the root of all evil

Is it?

Note: frame times at the end.

The conversion of all modules from SharpDX to PyOpenGL is finished, so I ran the test program again. Result: 430 FPS (previously 649). Time to optimize.

First: check with cprofile module. Most time spent is in the shaders uniforms update, then in the events raising.

  • After reducing some gpu calls, >> +20 FPS
  • Converting many For loops to list comprehensions and map() >> +10FPS

I was worried because the achievements in frames where small, then I remembered the events reporting.

  • After removing all the onRenderEnd calls, where I was doing rotation of the dragon and window title update >> +1000 FPS

The engine ended up running at 1500 FPS (max). Amazing, but unrealistic, since casting events is completely necessary. Maybe a threaded approach will give improvement in this point.

But since frame times is the right way to measure, I converted all numbers, getting:

  • First gain: 0.1ms
  • Second: 0.04ms
  • Last: 1.5ms

Was it right? After trying the same program in my slow laptop, the timings probed to be correct… and meaningless. All of them:
The result in my laptop was of 58FPS, when before the improvements was of 50FPS. Only 2.7ms Total, after all the stuff I did and removed.

Final result: I’m done with optimizations. Maybe, optimizing before having something good is not good. I will move on to the next step, that will not be an editor this time.

PyOpenGL performance 1

The first concern about rewriting the engine in Python + OpenGL was about having to learn one more language that in the beginning I didn’t wanted to learn. The speed of OpenGL was never any worry, mainly because I trusted in the findings of Valve.

The second concern, was Python speed. Being an interpreted language, it seemed that it was going to be inherently slower that C++ or even worst, slower than C#. Working with Basic.net previously, I was accustomed to the idea of having slow code, but SharpDX is being said to be not so distant to raw C++ in speed. And it proved to be truth after my initial tests, so… What to expect from PyOpenGL?

The first test I made was to load the Stanford dragon (after converting my meshes loader to Python, with Pyassimp) and the result was not satisfactory (or so I thought): The FPS is around 40 (up to 60 without recording), wich seemed to be slow, even in my slow laptop. Still, I could not say anything yet, until making a test in ‘the big one’ and having a comparison with SharpDX. After some days, here it is:

Amazing!

PyOpenGL 2/3.1 is faster than SharpDX (DX9), just like the C++ versions. Even better, I have not made any optimization to the Python version. I’m not using PyOpenGL-Accelerate nor Cython!, so it is possible to get even better speed with those tools 😀 .

The only real difference between the two tests is the shader used, but I doubt that the impact from it is that big.

For reference, the next data:

Graphics card: Nvidia GTX 560 se

Processor: Intel Core 2 Duo 2.6GB

OS: Windows 7 32 bits

Memory: 3GB

Direct X 9 without fixed function Pipeline and shader model 2

OpenGL 2 without fixed function Pipeline and GLSL 1.2

Max FPS without recording:

– DirectX: 570 (first)

– OpenGL: 649 (second)

dx9 ogl2

Something interesting is the fact that the OpenGL app will reduce its speed if the DirectX one is running, as seen on the “Both” part of the video. Also, the OGL will slow down with any movement of any window or any interaction with the desktop. The DX window will remain steady. Does that mean that Windows gives preference to DX tasks over OGL or was it my card?

In the PyOpenGL site, they accept the wrapper being slow, but for some deprecated features, that I’m not using anyway, so I’m safe from that. And with this results and the Cython option, I’m really happy, so the conversion continues.

Engine development pictures (2 months)

It’s been two months since Engendro3D started, so I think it deserves a small update on it’s current state.

Some screen caps, with and without lightmap:

screenshot_8_10_2013_22_3_50screenshot_8_10_2013_22_3_53


screenshot_8_10_2013_22_8_36screenshot_8_10_2013_22_8_38


screenshot_8_10_2013_22_8_55screenshot_8_10_2013_22_8_58


screenshot_8_10_2013_22_9_21 screenshot_8_10_2013_22_9_18


And two ducks, one spinning, with texture and simple lightning and the other with different scale, rotation, position and shader:

screenshot_8_10_2013_22_4_19

Importing the lightmap of the room (that I always use because is very high poly and detailed, so it gives me a decent measurement and look, while is simple to handle) took me some time, since I found no way of reading the second UV channel of my .x mesh using Assimp, so I ended up storing the 2nd UV channel in the vertex color and I extract it in a “pre-pass” step before loading the real model. I don’t really like that solution, but is fine for now.

There is also 2d and positional sound working (using SFML.net), basic input (with Windows default messages) and a basic camera as well.

Now I just need an editor, because placing everything by code is not fun. Once a basic one is ready, I’ll start with physics 😀 .