noufal
noufal

Reputation: 970

How to set a pixel in a SDL_surface?

I need to use the following function from this page. The SDL_Surface structure is defined as

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 */
} SDL_Surface;

The function is:

void set_pixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
      Uint8 *target_pixel = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
      *(Uint32 *)target_pixel = pixel;
}

Here I have few doubts, may be due to the lack of a real picture.

  1. Why do we need to multiply surface->pitch by y, and x by 4?
  2. What is the necessity of declaring target_pixel as an 8-bit integer pointer first, then casting it into a 32-bit integer pointer later?
  3. How does target_pixel retain the pixel value after the set_pixel function return?

Upvotes: 12

Views: 25156

Answers (2)

Soroush khoubyarian
Soroush khoubyarian

Reputation: 283

You can use the code below:

unsigned char* pixels = (unsigned char*)surface -> pixels;
pixels[4 * (y * surface -> w + x) + c] = 255;            

x is the x of the point you want, y is the y of the point and c shows what information you want:

c=0 corresponds to blue

c=1 corresponds to green

c=2 corresponds to red

c=3 corresponds to alpha(opacity)

Upvotes: 8

unwind
unwind

Reputation: 399823

  1. Since each pixel has size 4 (the surface is using Uint32-valued pixels), but the computation is being made in Uint8. The 4 is ugly, see below.
  2. To make the address calculation be in bytes.
  3. Since the pixel to be written really is 32-bit, the pointer must be 32-bit to make it a single write.

The calculation has to be in bytes since the surface's pitch field is in bytes.

Here's a (less aggressive than my initial attempt) re-write:

void set_pixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
  Uint32 * const target_pixel = (Uint32 *) ((Uint8 *) surface->pixels
                                             + y * surface->pitch
                                             + x * surface->format->BytesPerPixel);
  *target_pixel = pixel;
}

Note how we use surface->format->BytesPerPixel to factor out the 4. Magic constants are not a good idea. Also note that the above assumes that the surface really is using 32-bit pixels.

Upvotes: 12

Related Questions