9

I have a slight problem: I can't modify the pixels of an SDL screen.

Specifically, the following code doesn't work.

Uint32 * pixels = (Uint32 *) screen -> pixels; 
screen -> pixels = pixels;

This compiles, but it doesn't show anything. What am I missing?

Chris Frederick
  • 5,482
  • 3
  • 36
  • 44
nory
  • 91
  • 1
  • 1
  • 2

5 Answers5

23

I had the following functions lying around for setting pixels in an SDL_Surface. There are two versions each for 32-bit, 24-bit, 16-bit and 8-bit surfaces. If you just want to set a single pixel, you would use the normal versions. But if you want to set a bunch of pixels, first you lock the surface, then you use the nolock version(named so because it does not lock the surface), then you unlock. This way you aren't repeatedly locking and unlocking the surface, which is supposed to be an expensive operation, though I don't think I ever actually tested it.

void PutPixel32_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
    Uint8 * pixel = (Uint8*)surface->pixels;
    pixel += (y * surface->pitch) + (x * sizeof(Uint32));
    *((Uint32*)pixel) = color;
}

void PutPixel24_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
    Uint8 * pixel = (Uint8*)surface->pixels;
    pixel += (y * surface->pitch) + (x * sizeof(Uint8) * 3);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    pixel[0] = (color >> 24) & 0xFF;
    pixel[1] = (color >> 16) & 0xFF;
    pixel[2] = (color >> 8) & 0xFF;
#else
    pixel[0] = color & 0xFF;
    pixel[1] = (color >> 8) & 0xFF;
    pixel[2] = (color >> 16) & 0xFF;
#endif
}

void PutPixel16_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
    Uint8 * pixel = (Uint8*)surface->pixels;
    pixel += (y * surface->pitch) + (x * sizeof(Uint16));
    *((Uint16*)pixel) = color & 0xFFFF;
}

void PutPixel8_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
    Uint8 * pixel = (Uint8*)surface->pixels;
    pixel += (y * surface->pitch) + (x * sizeof(Uint8));
    *pixel = color & 0xFF;
}

void PutPixel32(SDL_Surface * surface, int x, int y, Uint32 color)
{
    if( SDL_MUSTLOCK(surface) )
        SDL_LockSurface(surface);
    PutPixel32_nolock(surface, x, y, color);
    if( SDL_MUSTLOCK(surface) )
        SDL_UnlockSurface(surface);
}

void PutPixel24(SDL_Surface * surface, int x, int y, Uint32 color)
{
    if( SDL_MUSTLOCK(surface) )
        SDL_LockSurface(surface);
    PutPixel24_nolock(surface, x, y, color);
    if( SDL_MUSTLOCK(surface) )
        SDL_LockSurface(surface);
}

void PutPixel16(SDL_Surface * surface, int x, int y, Uint32 color)
{
    if( SDL_MUSTLOCK(surface) )
        SDL_LockSurface(surface);
    PutPixel16_nolock(surface, x, y, color);
    if( SDL_MUSTLOCK(surface) )
        SDL_UnlockSurface(surface);
}

void PutPixel8(SDL_Surface * surface, int x, int y, Uint32 color)
{
    if( SDL_MUSTLOCK(surface) )
        SDL_LockSurface(surface);
    PutPixel8_nolock(surface, x, y, color);
    if( SDL_MUSTLOCK(surface) )
        SDL_UnlockSurface(surface);
}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • 3
    I know this is an old question/answer, but I would like to point out that the program will crash if you try to grab a pixel that is outside the bounds of the surface. For instance, trying to get a pixel at an X coordinate of 64 from a 64 width surface will crash because the last pixel is at 63. – TyCobb Feb 13 '13 at 05:49
2

Manipulating the contents of screen->pixels will modify pixels, with a couple of caveats.

First, as you've shown in the code snippet, note that screen->pixels is a pointer to the pixel data of the surface. The pixel data itself is accessed as a linear array from that pointer based on the width of the surface (surface->pitch) and the size of the pixel in bytes. The pixel size (aka depth) is set during initialisation, using SDL_SetVideoMode() and can be found in screen->format->BytesPerPixel.

Locking of the surface before making changes may be necessary.

In addition, depending on the options that were passed to SDL_SetVideoMode() you may also need to call SDL_Flip() to display the changes that you've made.

A working example of pixel manipulation can be found here.


As has been pointed out in the comments, the code listed in the question is not actually going to do anything visible as no changes are being made to the pixel data.

Andrew Edgecombe
  • 39,594
  • 3
  • 35
  • 61
1

Adding an SDL2 variant manipulating pixels not on a surface but in a renderer (and which does not crash if you try to manipulate pixels outside of your screen, unlike previous answers)

void putPixelRGB(SDL_Renderer* renderer, int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
    SDL_SetRenderDrawColor(renderer, (Uint8)r, (Uint8)g, (Uint8)b, 255);
    SDL_RenderDrawPoint(renderer, x, y);
}
Martin G
  • 17,357
  • 9
  • 82
  • 98
-3

why change a pixel?

make a new surface & a Rect

// CODE ------------>

SDL_Surface *screen, *PIXEL = NULL;

SDL_Rect PIXELRect;
PIXELRect.h=5;
PIXELRect.w=5;
PIXELRect.x=100;
PIXELRect.y=100;

screen = SDL_SetVideoMode(640, 468, 32, SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_ANYFORMAT);

while(running){
SDL_FillRect(screen, &PIXELRect, (#color));
}
-3

You must not modify the contents of the SDL_Surface structure. If you want to copy the pixels you should malloc() some memory and then memcpy() the pixels.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • but my goal is to mess around with the pixels – nory Jul 27 '11 at 22:58
  • Can you clarify _why_ we **must not modify** the contents of the SDL_Surface? Will/could it lead to bugs/unexpected behavior? – snapfractalpop Oct 12 '12 at 18:21
  • @snapfractalpop: From the `SDL_video.h` file: "This structure [SDL_Surface] should be treated as read-only, except for 'pixels' [...] ". If you do not comply you are breaking the struct invariant and so the library will fail to work correctly. – rodrigo Oct 12 '12 at 21:46
  • 1
    Thanks for the info. I was only concerned with reading/writing to the pixel data (which appears OK if we use `SDL_LockSurface`). – snapfractalpop Oct 16 '12 at 19:06
  • -1, you can definitely modify *pixels* part of the SDL_Surface structure. –  Mar 28 '13 at 09:25