1
votes

I'm attempting to use SDL to make a monochrome image appear on screen. So the array I have will either have values of 0x00 or 0xFF.

To start I've make a small 200x200 window, created a new surface, use FillRect to just make it black. When I print out the pitch and pixel format I get 800 for the pitch and rgb888 for the format. If I am understanding this right, this means that the dimensions of surface->pixels is 800x200 because each pixel has an additional 2 bytes of information attached to it?

What I don't understand is if I want to change that surface pixel array to something totally different, what is the format of the array? If I had a simple array of one pixel [0xFF], would the one formatted for the RGB values of the surface be [0xFF, 0xFF, 0xFF]? For each pixel I want to change on the screen I need to update three values in the array?

After I figure out how to format the array is it as simple as surface->pixels = newArray? Then update the window surface after?

1

1 Answers

1
votes

Look at SDL_pixels.h:

#define SDL_DEFINE_PIXELFORMAT(type, order, layout, bits, bytes) \
    ((1 << 28) | ((type) << 24) | ((order) << 20) | ((layout) << 16) | \
     ((bits) << 8) | ((bytes) << 0))

And, for RGB888, we have:

    SDL_PIXELFORMAT_RGB888 =
        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XRGB,
                               SDL_PACKEDLAYOUT_8888, 24, 4),

For SDL_PACKEDORDER_*, we have:

/** Packed component order, high bit -> low bit. */

So, each pixel is a [packed] 32 unsigned int, and the order when fetched into a 32 bit integer is:

X | R | G | B

For a little endian machine, the order is reversed when in memory:

B | G | R | X

However, see the caveat below ...


If I am understanding this right, this means that the dimensions of surface->pixels is 800x200 because each pixel has an additional 2 bytes of information attached to it?

No, each pixel is 4 bytes, which only has 3 [useful] values (as viewed in a 32 bit integer as above).

The equation is:

pitch = number_of_bytes_per_pixel_in_memory * width

Which, for you, is: 800 = 4 * 200


The format can change the ordering of the RGB bytes, and whether the fourth byte has anything of value (e.g. transparency/alpha blend which it would for an RGBA format).

For RGB888, here are some conversion functions that I cooked up for illustration:

typedef unsigned int u32;
typedef unsigned char byte;

enum {
    RSHF = 16,
    GSHF = 8,
    BSHF = 0,
};

// rgb2pixel -- convert RGB values to pixel value
u32
rgb2pixel(byte r,byte g,byte b)
{
    u32 pix;

    pix = 0;
    pix |= ((u32) r) << RSHF;
    pix |= ((u32) g) << GSHF;
    pix |= ((u32) b) << BSHF;

    return pix;
}

// pix2red -- extract red from RGB pixel
byte
pix2red(u32 pix)
{
    byte color;

    color = pix >> RSHF;

    return color;
}

// pix2green -- extract green from RGB pixel
byte
pix2green(u32 pix)
{
    byte color;

    color = pix >> GSHF;

    return color;
}

// pix2blue -- extract blue from RGB pixel
byte
pix2blue(u32 pix)
{
    byte color;

    color = pix >> BSHF;

    return color;
}

Caveat: I'm not totally sure what "Packed component order" means.

My interpretation of the order above assumes it's the order after the pixel has been fetched as a 32 bit integer value.

But, it could mean that it's the in-memory order, in which case the diagrams I created above would be reversed.

If you stored all values from:

rgb2pixel(0xFF,0x00,0x00)

You should get a red background. If you got blue instead, then, RSHF and BSHF should be interchanged.