PySDL2 issue with SDL_Surface / LP_SDL_Surface
Asked Answered
T

1

6

Im running win7 with python 3.3 and PySDL2 0.5. When creating surfaces (no matter what method) i get an LP_SDL_Surface instead of a SDL_Surface. The LP_SDL_Surface lacks any of the methods and attribute you would expect it to have. Here is the issue using example code from the documentation:

import os
os.environ["PYSDL2_DLL_PATH"] = os.path.dirname(os.path.abspath(__file__))

import sys
import ctypes
from sdl2 import *

def main():
    SDL_Init(SDL_INIT_VIDEO)
    window = SDL_CreateWindow(b"Hello World",
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              592, 460, SDL_WINDOW_SHOWN)
    windowsurface = SDL_GetWindowSurface(window)

    image = SDL_LoadBMP(b"exampleimage.bmp")
    SDL_BlitSurface(image, None, windowsurface, None)
    print(image.h)

    SDL_UpdateWindowSurface(window)
    SDL_FreeSurface(image)

    running = True
    event = SDL_Event()
    while running:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT:
                running = False
                break

    SDL_DestroyWindow(window)
    SDL_Quit()
    return 0

if __name__ == "__main__":
    sys.exit(main())

and the traceback is:

Traceback (most recent call last):
File "C:/.../test.py", line 35, in <module>
sys.exit(main())
File "C:/.../test.py", line 17, in main
print(image.h)
AttributeError: 'LP_SDL_Surface' object has no attribute 'h'

A google search for "LP_SDL_Surface" brings 0 (!) results.

Telespectroscope answered 19/8, 2013 at 22:7 Comment(4)
i have found out that LP_* is a ctypes thing and means (long) pointer to *. realizing this i checked the python ctypes documentation and now use the content attribute to get to the surface itself. so i guess the issue is solved, im still unsure that this is intended behavior though.Telespectroscope
could you please elaborate on your solution? I'm having this issue as well. Using surface.contents gives me a null pointer access error.Billybillycock
sure, or even better, see the explanation i got from Marcus von Appen i got on the sdl forums: forums.libsdl.org/viewtopic.php?t=9419Telespectroscope
@Telespectroscope you can put it as answer.Pentose
S
3

If you work with the lower level SDL methods (e.g. sdl2.SDL_LoadBMP) you will have to deal with ctypes conversions, referencing(byref) and dereferencing of pointers (.contents, .value).

So for the specific question, as you've already commented, using print(image.contents.h) would be enough.

There are some higher level classes and methods provided by pysdl2 (sdl2.ext), however, that could do most of those conversions for you, if desired. The code below achieves the same goal without having to touch ctypes:

import os
os.environ["PYSDL2_DLL_PATH"] = os.path.dirname(os.path.abspath(__file__))

import sys
import sdl2
import sdl2.ext

def main():
    sdl2.ext.init()
    window = sdl2.ext.Window(
        title="Hello World!", size=(592, 460), flags=sdl2.SDL_WINDOW_SHOWN,
        position=(sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED))

    window.show()

    renderer = sdl2.ext.Renderer(window)
    factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=renderer)
    spriterenderer = factory.create_sprite_render_system(window)

    image = factory.from_image("exampleimage.bmp")
    print(image.size[1])  # image.size = (w, h)

    running = True
    while running:
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_QUIT:
                running = False
                break
        spriterenderer.render(image)

    sdl2.ext.quit()
    return 0

if __name__ == '__main__':
    sys.exit(main())

It also makes use of texture rendering, using hardware acceleration, instead of surface blitting (software based).

Finally, using the higher level sdl2.ext you could also instantiate classes (instead of having to write a whole new sprite class yourself) like sdl2.ext.sprite.TextureSprite, and implement a h property:

class TextureSprite(sdl2.ext.TextureSprite):

    @property
    def h(self):
        """The height of the TextureSprite."""
        return self.size[1]

    @property
    def w(self):
        """The width of the TextureSprite."""
        return self.size[0]
Spinous answered 20/12, 2016 at 5:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.