Description
I think that information related to a pixel format should not live within a surface using that format but rather in its own struct. Since it's not dynamically changing data, a dataclass is good enough for this job. Things like palette, pitch or colorkey can stay with their surface. Below is what I think is information that makes sense to give to the user, as dataclass properties. Note that this information is available with SDL2 and SDL3, absolutely not restricted to sdl3.
- format enum: probably not used much but the only information relevant if we want to use this pixel format in other parts of Surface
- format name: the only way for a user to understand the format. it tells if it's RGBA or ABGR and so on. Keep in mind we just need to use
SDL_GetPixelFormatName
and then remove theSDL_PIXELFORMAT_
prefix. - masks: an important raw representation of the format color order
- shifts: information about how to get a color channel from a mapped color
- bitsize/bytesize: the depth of the color, quite useful also considering some of our transforms only work with 32bit depth
- is_alpha: while sdl provides an interesting chunk of macros (is fourcc, is HDR, is indexed/packed/array, is float) I think this one is the most useful for a pygamer, as it could effectively tell them if the format has an alpha channel, regardless of the bitsize.
Getting this info from SDL2 or SDL3 is trivial: for SDL2, you just need to SDL_AllocFormat
and SDL_FreeFormat
from a format enum, to gather all the data. In SDL3 it's easier, because given a format enum, you only need SDL_GetPixelFormatDetails
. Then the struct attributes are almost identical.
The PixelFormat should be a dataclass populated in C. the function populating it should be pygame.surface.get_pixel_format
. It would be rather flexible, as it accepts:
- an int: means the user somehow already knows the enum value. cheers for them!
- a string: SDL_PIXELFORMAT_RGBA32 would be represented by the "rgba32" string. there is no way to have this without a massive strcmp tower
- a tuple: if that's the case, we assume the user is passing in a tuple of masks. We will use the corresponding SDL functions (
SDL_MasksToPixelFormatEnum
for SDL2 andSDL_GetPixelFormatForMasks
for SDL3)
If a strcmp tower doesn't inspire you, then we need to export some formats as pygame constants - I'm totally fine with it, but we have to choose what formats we want, as there are many obscure indexed formats pygame doesn't usually use. In general the formats supported by the string or the constants should be the common elements of the SDL2 and the SDL3 formats, with the possibility of adding more formats when sdl3 is the only one used.
Then, regarding surface, it should have this: Surface.get_format
returning an instance of that dataclass. Why not a property? Because getting the format requires allocating SDL memory and allocating a new python object, it should be called once per set of operations (it's not an expensive call, but still).
How would it be used?
- Information. maybe you have a bug with alpha, or your numpy/opengl buffers are behaving strange, so you want to check just how the pixels are arranged.
- To make a new surface. right now you can pass masks and depth, but personally, I wouldn't know how to use the masks for the format I want, I'd have to search online or ask AI. if you can make a pixelformat instance from a string/constant, then it's much more intuitive
- To convert a surface, following the same principle.
How would init and convert know you are doing that? If the masks is not another surface, and is not a sequence, then the C code will check if the passed object has a format
attribute. If that's the case, it will try to use it to get the SDL format enum, to enforce the format. That means that a new sort of protocol for what the masks can be is added in the stubs, and it would be perfectly backwards compatible.
That's all I have thought for now, I can't wait to hear your thoughts.