7
\$\begingroup\$

I'm trying to use SDL_LockTexture and SDL_UnlockTexture for directly editing pixels in a texture. I'm using SDL 2.0. Setting the pixel value using the following code doesn't modify the texture:

void *pixels;
int pitch;

SDL_LockTexture(mytexture, NULL, &pixels, &pitch);

// Set pixel 100,100 to blue
((uint32_t *)pixels)[100 * 100] = 255;

SDL_UnlockTexture(mytexture);
\$\endgroup\$
  • \$\begingroup\$ What is the return value of SDL_LockTexture(...);? \$\endgroup\$ – Jon Apr 20 '15 at 8:19
2
\$\begingroup\$

Colouring SDL textures might be a little tricky. The following code should outline the main points of colouring a texture. The key is to fetch all required data from SDL before starting to alter the texture.

Uint32* pixels = nullptr;
int pitch = 0;
int format;

// Get the size of the texture.
int w, h;
SDL_QueryTexture(texture, &format, nullptr, &w, &h);

// Now let's make our "pixels" pointer point to the texture data.
if (SDL_LockTexture(texture, nullptr, (void**)&pixels, &pitch))
{
    // If the locking fails, you might want to handle it somehow. SDL_GetError(); or something here.
}

SDL_PixelFormat pixelFormat;
pixelFormat.format = format;
// Now you want to format the color to a correct format that SDL can use.
// Basically we convert our RGB color to a hex-like BGR color.
Uint32 color = SDL_MapRGB(&pixelFormat, R, G, B);

// Before setting the color, we need to know where we have to place it.
Uint32 pixelPosition = y * (pitch / sizeof(unsigned int)) + x;

// Now we can set the pixel(s) we want.
pixels[pixelPosition] = color;

// Also don't forget to unlock your texture once you're done.
SDL_UnlockTexture(texture);

Now, you should also note that modifying textures in code is relatively expensive. Also the code is not very clean, as editing C++ int pointer arrays and translating colours into different formats can cause problems, as what goes on where might not be as clear as needed. However doing this only when absolutely necessary shouldn't cause too much problems.

You also might want to consider using SDL_SetRenderTarget and modifying the texture by rendering to it. However for some tasks, rendering primitives to the texture might not be an option, and that's a case when modifying the pixels like this might be come handy.

\$\endgroup\$
  • 1
    \$\begingroup\$ 1. Wrong approach entirely, don't touch pixels on Textures, that what Surfaces are for. -- 2. Use SDL_MapRGB to compute colors, it's not safe to assume everything is 32-bit RGBA -- 3. Use surface->BytesPerPixel, it's not safe to assume... etc \$\endgroup\$ – MickLH Oct 2 '15 at 14:14
  • \$\begingroup\$ Passing around surfaces and keeping those in the memory is not worth the effort IMHO, modifying textures andor surfaces is something that should be performed rarely, so passing pixels to the GPU isn't a deal-breaker here. However the SDL_MapRGB is a valid point. \$\endgroup\$ – Tyyppi_77 Oct 2 '15 at 14:20
-1
\$\begingroup\$

incorrect- you need the "surface" format details from the texture- before one can blindly use MapRGB.

To get the data- you query the Texture- as outlined above.

MapRGB expects surface->format (in my case surface^.format) to be handed to it. check (SDL syntax in the header files)

Rendering to the texture is the SDL2 more efficient way. you generally batch render- dont update single pixels- (at least not until the next screen refresh). A lot of people OVER Render and realize it. Dont present until the screen (the monitor) is ready for it- doing so causes "flicker". Personally, Id wait until whatever is rendering to finish....then prepare the next batch of ops.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.