Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a pixel in a SDL_surface?

Tags:

c++

c

graphics

sdl

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?
like image 210
noufal Avatar asked Nov 19 '13 11:11

noufal


2 Answers

  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.

like image 113
unwind Avatar answered Nov 05 '22 15:11

unwind


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:
if c == 0 >>> blue
if c == 1 >>> green
if c == 2 >>> red
if c == 3 >>> alpha(opacity)

like image 25
Soroush khoubyarian Avatar answered Nov 05 '22 13:11

Soroush khoubyarian