You are not logged in.
I'm trying to use ctypes to interface with SDL. More specifically, I'm trying to modify the pixel data on the SDL_Surface created by SDL_SetVideoMode, which returns a pointer to that surface.
Well, in Python 3.x (and probably 2.x ... I'm using 3), using ctypes to call SDL_SetVideoMode returns an integer that specifies an address, and that can be turned into a pointer like so:
p_surface = ctypes.cast(addr_surface, ctypes.POINTER(ctypes.c_uint))
# I can now dereference with a proper offset (based on the memory layout of the SDL_Surface structure)
# to read stuff like width and height, which works as expected:
print("Screen width: {:d}".format(p_surface[2]))
print("Screen height: {:d}".format(p_surface[3]))
Now, here's the part that stumps me:
According to the documentation for SDL_Surface, it looks like this:
typedef struct SDL_Surface {
Uint32 flags; /* Read-only */
SDL_PixelFormat *format; /* Read-only */
int w, h; /* Read-only */
Uint16 pitch; /* Read-only */
void *pixels; /* Read-write */
SDL_Rect clip_rect; /* Read-only */
int refcount; /* Read-mostly */
/* This structure also contains private fields not shown here */
} SDL_Surface;
So, I figure that the pointer to pixels starts on byte addr_surface + 18 (4 ints at 4 bytes each, and one short at 2 bytes), and that I could use that information to get access to actual pixels:
pp_pixels = ctypes.cast(addr_surface + 18, ctypes.POINTER(ctypes.c_uint))
p_pixels = ctypes.cast(pp_pixels[0], ctypes.POINTER(ctypes.c_char))
p_pixels[0] # should give me the value of first byte for the first pixel, but instead I get a segfault
Anyone have any ideas as to why this is happening? I would appreciate any insight.
Last edited by Goran (2012-08-04 23:58:07)
Offline
So, I figure that the pointer to pixels starts on byte addr_surface + 18
You can't make any assumptions about the storage of fields inside a struct unless you have documentation to prove it. What's logical isn't good enough.
However, I might imagine that there's padding on that Uint16 to avoid misaligning the pointer on an address that's not a multiple of 4, so you could try addr_surface + 20 instead. But the only way to be sure is to find documentation (or write a test program in C that uses offsetof).
Offline
Seems like you were right. I tried the whole operation with addr_surface + 20, and it worked as expected.
In studying ctypes a little further, I found a much better way:
class SDL_Surface(Structure):
_fields_ = [
("fields", c_uint32),
("format", c_void_p),
("w", c_int),
("h", c_int),
("pitch", c_uint16),
("pixels", POINTER(c_char))
]
sdl.SDL_SetVideoMode.restype = POINTER(SDL_Surface)
p_surface = sdl.SDL_SetVideoMode(128, 128, 24, 0)
surface = p_surface.contents # copies portion of the structure defined in _fields_
surface.pixels[0] # gets the value of first byte in first pixel.
It works really well.
Thanks for your help, Trent.
Last edited by Goran (2012-08-05 00:13:26)
Offline